...
Run Format

Source file src/go/types/stmt.go

     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.
     4	
     5	// This file implements typechecking of statements.
     6	
     7	package types
     8	
     9	import (
    10		"fmt"
    11		"go/ast"
    12		"go/constant"
    13		"go/token"
    14	)
    15	
    16	func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *ast.BlockStmt) {
    17		if trace {
    18			if name == "" {
    19				name = "<function literal>"
    20			}
    21			fmt.Printf("--- %s: %s {\n", name, sig)
    22			defer fmt.Println("--- <end>")
    23		}
    24	
    25		// set function scope extent
    26		sig.scope.pos = body.Pos()
    27		sig.scope.end = body.End()
    28	
    29		// save/restore current context and setup function context
    30		// (and use 0 indentation at function start)
    31		defer func(ctxt context, indent int) {
    32			check.context = ctxt
    33			check.indent = indent
    34		}(check.context, check.indent)
    35		check.context = context{
    36			decl:  decl,
    37			scope: sig.scope,
    38			sig:   sig,
    39		}
    40		check.indent = 0
    41	
    42		check.stmtList(0, body.List)
    43	
    44		if check.hasLabel {
    45			check.labels(body)
    46		}
    47	
    48		if sig.results.Len() > 0 && !check.isTerminating(body, "") {
    49			check.error(body.Rbrace, "missing return")
    50		}
    51	
    52		// spec: "Implementation restriction: A compiler may make it illegal to
    53		// declare a variable inside a function body if the variable is never used."
    54		// (One could check each scope after use, but that distributes this check
    55		// over several places because CloseScope is not always called explicitly.)
    56		check.usage(sig.scope)
    57	}
    58	
    59	func (check *Checker) usage(scope *Scope) {
    60		for _, obj := range scope.elems {
    61			if v, _ := obj.(*Var); v != nil && !v.used {
    62				check.softErrorf(v.pos, "%s declared but not used", v.name)
    63			}
    64		}
    65		for _, scope := range scope.children {
    66			check.usage(scope)
    67		}
    68	}
    69	
    70	// stmtContext is a bitset describing which
    71	// control-flow statements are permissible,
    72	// and provides additional context information
    73	// for better error messages.
    74	type stmtContext uint
    75	
    76	const (
    77		// permissible control-flow statements
    78		breakOk stmtContext = 1 << iota
    79		continueOk
    80		fallthroughOk
    81	
    82		// additional context information
    83		finalSwitchCase
    84	)
    85	
    86	func (check *Checker) simpleStmt(s ast.Stmt) {
    87		if s != nil {
    88			check.stmt(0, s)
    89		}
    90	}
    91	
    92	func trimTrailingEmptyStmts(list []ast.Stmt) []ast.Stmt {
    93		for i := len(list); i > 0; i-- {
    94			if _, ok := list[i-1].(*ast.EmptyStmt); !ok {
    95				return list[:i]
    96			}
    97		}
    98		return nil
    99	}
   100	
   101	func (check *Checker) stmtList(ctxt stmtContext, list []ast.Stmt) {
   102		ok := ctxt&fallthroughOk != 0
   103		inner := ctxt &^ fallthroughOk
   104		list = trimTrailingEmptyStmts(list) // trailing empty statements are "invisible" to fallthrough analysis
   105		for i, s := range list {
   106			inner := inner
   107			if ok && i+1 == len(list) {
   108				inner |= fallthroughOk
   109			}
   110			check.stmt(inner, s)
   111		}
   112	}
   113	
   114	func (check *Checker) multipleDefaults(list []ast.Stmt) {
   115		var first ast.Stmt
   116		for _, s := range list {
   117			var d ast.Stmt
   118			switch c := s.(type) {
   119			case *ast.CaseClause:
   120				if len(c.List) == 0 {
   121					d = s
   122				}
   123			case *ast.CommClause:
   124				if c.Comm == nil {
   125					d = s
   126				}
   127			default:
   128				check.invalidAST(s.Pos(), "case/communication clause expected")
   129			}
   130			if d != nil {
   131				if first != nil {
   132					check.errorf(d.Pos(), "multiple defaults (first at %s)", check.fset.Position(first.Pos()))
   133				} else {
   134					first = d
   135				}
   136			}
   137		}
   138	}
   139	
   140	func (check *Checker) openScope(s ast.Stmt, comment string) {
   141		scope := NewScope(check.scope, s.Pos(), s.End(), comment)
   142		check.recordScope(s, scope)
   143		check.scope = scope
   144	}
   145	
   146	func (check *Checker) closeScope() {
   147		check.scope = check.scope.Parent()
   148	}
   149	
   150	func assignOp(op token.Token) token.Token {
   151		// token_test.go verifies the token ordering this function relies on
   152		if token.ADD_ASSIGN <= op && op <= token.AND_NOT_ASSIGN {
   153			return op + (token.ADD - token.ADD_ASSIGN)
   154		}
   155		return token.ILLEGAL
   156	}
   157	
   158	func (check *Checker) suspendedCall(keyword string, call *ast.CallExpr) {
   159		var x operand
   160		var msg string
   161		switch check.rawExpr(&x, call, nil) {
   162		case conversion:
   163			msg = "requires function call, not conversion"
   164		case expression:
   165			msg = "discards result of"
   166		case statement:
   167			return
   168		default:
   169			unreachable()
   170		}
   171		check.errorf(x.pos(), "%s %s %s", keyword, msg, &x)
   172	}
   173	
   174	// goVal returns the Go value for val, or nil.
   175	func goVal(val constant.Value) interface{} {
   176		// val should exist, but be conservative and check
   177		if val == nil {
   178			return nil
   179		}
   180		// Match implementation restriction of other compilers.
   181		// gc only checks duplicates for integer, floating-point
   182		// and string values, so only create Go values for these
   183		// types.
   184		switch val.Kind() {
   185		case constant.Int:
   186			if x, ok := constant.Int64Val(val); ok {
   187				return x
   188			}
   189			if x, ok := constant.Uint64Val(val); ok {
   190				return x
   191			}
   192		case constant.Float:
   193			if x, ok := constant.Float64Val(val); ok {
   194				return x
   195			}
   196		case constant.String:
   197			return constant.StringVal(val)
   198		}
   199		return nil
   200	}
   201	
   202	// A valueMap maps a case value (of a basic Go type) to a list of positions
   203	// where the same case value appeared, together with the corresponding case
   204	// types.
   205	// Since two case values may have the same "underlying" value but different
   206	// types we need to also check the value's types (e.g., byte(1) vs myByte(1))
   207	// when the switch expression is of interface type.
   208	type (
   209		valueMap  map[interface{}][]valueType // underlying Go value -> valueType
   210		valueType struct {
   211			pos token.Pos
   212			typ Type
   213		}
   214	)
   215	
   216	func (check *Checker) caseValues(x *operand, values []ast.Expr, seen valueMap) {
   217	L:
   218		for _, e := range values {
   219			var v operand
   220			check.expr(&v, e)
   221			if x.mode == invalid || v.mode == invalid {
   222				continue L
   223			}
   224			check.convertUntyped(&v, x.typ)
   225			if v.mode == invalid {
   226				continue L
   227			}
   228			// Order matters: By comparing v against x, error positions are at the case values.
   229			res := v // keep original v unchanged
   230			check.comparison(&res, x, token.EQL)
   231			if res.mode == invalid {
   232				continue L
   233			}
   234			if v.mode != constant_ {
   235				continue L // we're done
   236			}
   237			// look for duplicate values
   238			if val := goVal(v.val); val != nil {
   239				if list := seen[val]; list != nil {
   240					// look for duplicate types for a given value
   241					// (quadratic algorithm, but these lists tend to be very short)
   242					for _, vt := range list {
   243						if Identical(v.typ, vt.typ) {
   244							check.errorf(v.pos(), "duplicate case %s in expression switch", &v)
   245							check.error(vt.pos, "\tprevious case") // secondary error, \t indented
   246							continue L
   247						}
   248					}
   249				}
   250				seen[val] = append(seen[val], valueType{v.pos(), v.typ})
   251			}
   252		}
   253	}
   254	
   255	func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []ast.Expr, seen map[Type]token.Pos) (T Type) {
   256	L:
   257		for _, e := range types {
   258			T = check.typOrNil(e)
   259			if T == Typ[Invalid] {
   260				continue L
   261			}
   262			// look for duplicate types
   263			// (quadratic algorithm, but type switches tend to be reasonably small)
   264			for t, pos := range seen {
   265				if T == nil && t == nil || T != nil && t != nil && Identical(T, t) {
   266					// talk about "case" rather than "type" because of nil case
   267					Ts := "nil"
   268					if T != nil {
   269						Ts = T.String()
   270					}
   271					check.errorf(e.Pos(), "duplicate case %s in type switch", Ts)
   272					check.error(pos, "\tprevious case") // secondary error, \t indented
   273					continue L
   274				}
   275			}
   276			seen[T] = e.Pos()
   277			if T != nil {
   278				check.typeAssertion(e.Pos(), x, xtyp, T)
   279			}
   280		}
   281		return
   282	}
   283	
   284	// stmt typechecks statement s.
   285	func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
   286		// statements cannot use iota in general
   287		// (constant declarations set it explicitly)
   288		assert(check.iota == nil)
   289	
   290		// statements must end with the same top scope as they started with
   291		if debug {
   292			defer func(scope *Scope) {
   293				// don't check if code is panicking
   294				if p := recover(); p != nil {
   295					panic(p)
   296				}
   297				assert(scope == check.scope)
   298			}(check.scope)
   299		}
   300	
   301		inner := ctxt &^ (fallthroughOk | finalSwitchCase)
   302		switch s := s.(type) {
   303		case *ast.BadStmt, *ast.EmptyStmt:
   304			// ignore
   305	
   306		case *ast.DeclStmt:
   307			check.declStmt(s.Decl)
   308	
   309		case *ast.LabeledStmt:
   310			check.hasLabel = true
   311			check.stmt(ctxt, s.Stmt)
   312	
   313		case *ast.ExprStmt:
   314			// spec: "With the exception of specific built-in functions,
   315			// function and method calls and receive operations can appear
   316			// in statement context. Such statements may be parenthesized."
   317			var x operand
   318			kind := check.rawExpr(&x, s.X, nil)
   319			var msg string
   320			switch x.mode {
   321			default:
   322				if kind == statement {
   323					return
   324				}
   325				msg = "is not used"
   326			case builtin:
   327				msg = "must be called"
   328			case typexpr:
   329				msg = "is not an expression"
   330			}
   331			check.errorf(x.pos(), "%s %s", &x, msg)
   332	
   333		case *ast.SendStmt:
   334			var ch, x operand
   335			check.expr(&ch, s.Chan)
   336			check.expr(&x, s.Value)
   337			if ch.mode == invalid || x.mode == invalid {
   338				return
   339			}
   340	
   341			tch, ok := ch.typ.Underlying().(*Chan)
   342			if !ok {
   343				check.invalidOp(s.Arrow, "cannot send to non-chan type %s", ch.typ)
   344				return
   345			}
   346	
   347			if tch.dir == RecvOnly {
   348				check.invalidOp(s.Arrow, "cannot send to receive-only type %s", tch)
   349				return
   350			}
   351	
   352			check.assignment(&x, tch.elem, "send")
   353	
   354		case *ast.IncDecStmt:
   355			var op token.Token
   356			switch s.Tok {
   357			case token.INC:
   358				op = token.ADD
   359			case token.DEC:
   360				op = token.SUB
   361			default:
   362				check.invalidAST(s.TokPos, "unknown inc/dec operation %s", s.Tok)
   363				return
   364			}
   365	
   366			var x operand
   367			check.expr(&x, s.X)
   368			if x.mode == invalid {
   369				return
   370			}
   371			if !isNumeric(x.typ) {
   372				check.invalidOp(s.X.Pos(), "%s%s (non-numeric type %s)", s.X, s.Tok, x.typ)
   373				return
   374			}
   375	
   376			Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"} // use x's position
   377			check.binary(&x, nil, s.X, Y, op)
   378			if x.mode == invalid {
   379				return
   380			}
   381			check.assignVar(s.X, &x)
   382	
   383		case *ast.AssignStmt:
   384			switch s.Tok {
   385			case token.ASSIGN, token.DEFINE:
   386				if len(s.Lhs) == 0 {
   387					check.invalidAST(s.Pos(), "missing lhs in assignment")
   388					return
   389				}
   390				if s.Tok == token.DEFINE {
   391					check.shortVarDecl(s.TokPos, s.Lhs, s.Rhs)
   392				} else {
   393					// regular assignment
   394					check.assignVars(s.Lhs, s.Rhs)
   395				}
   396	
   397			default:
   398				// assignment operations
   399				if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
   400					check.errorf(s.TokPos, "assignment operation %s requires single-valued expressions", s.Tok)
   401					return
   402				}
   403				op := assignOp(s.Tok)
   404				if op == token.ILLEGAL {
   405					check.invalidAST(s.TokPos, "unknown assignment operation %s", s.Tok)
   406					return
   407				}
   408				var x operand
   409				check.binary(&x, nil, s.Lhs[0], s.Rhs[0], op)
   410				if x.mode == invalid {
   411					return
   412				}
   413				check.assignVar(s.Lhs[0], &x)
   414			}
   415	
   416		case *ast.GoStmt:
   417			check.suspendedCall("go", s.Call)
   418	
   419		case *ast.DeferStmt:
   420			check.suspendedCall("defer", s.Call)
   421	
   422		case *ast.ReturnStmt:
   423			res := check.sig.results
   424			if res.Len() > 0 {
   425				// function returns results
   426				// (if one, say the first, result parameter is named, all of them are named)
   427				if len(s.Results) == 0 && res.vars[0].name != "" {
   428					// spec: "Implementation restriction: A compiler may disallow an empty expression
   429					// list in a "return" statement if a different entity (constant, type, or variable)
   430					// with the same name as a result parameter is in scope at the place of the return."
   431					for _, obj := range res.vars {
   432						if _, alt := check.scope.LookupParent(obj.name, check.pos); alt != nil && alt != obj {
   433							check.errorf(s.Pos(), "result parameter %s not in scope at return", obj.name)
   434							check.errorf(alt.Pos(), "\tinner declaration of %s", obj)
   435							// ok to continue
   436						}
   437					}
   438				} else {
   439					// return has results or result parameters are unnamed
   440					check.initVars(res.vars, s.Results, s.Return)
   441				}
   442			} else if len(s.Results) > 0 {
   443				check.error(s.Results[0].Pos(), "no result values expected")
   444				check.use(s.Results...)
   445			}
   446	
   447		case *ast.BranchStmt:
   448			if s.Label != nil {
   449				check.hasLabel = true
   450				return // checked in 2nd pass (check.labels)
   451			}
   452			switch s.Tok {
   453			case token.BREAK:
   454				if ctxt&breakOk == 0 {
   455					check.error(s.Pos(), "break not in for, switch, or select statement")
   456				}
   457			case token.CONTINUE:
   458				if ctxt&continueOk == 0 {
   459					check.error(s.Pos(), "continue not in for statement")
   460				}
   461			case token.FALLTHROUGH:
   462				if ctxt&fallthroughOk == 0 {
   463					msg := "fallthrough statement out of place"
   464					if ctxt&finalSwitchCase != 0 {
   465						msg = "cannot fallthrough final case in switch"
   466					}
   467					check.error(s.Pos(), msg)
   468				}
   469			default:
   470				check.invalidAST(s.Pos(), "branch statement: %s", s.Tok)
   471			}
   472	
   473		case *ast.BlockStmt:
   474			check.openScope(s, "block")
   475			defer check.closeScope()
   476	
   477			check.stmtList(inner, s.List)
   478	
   479		case *ast.IfStmt:
   480			check.openScope(s, "if")
   481			defer check.closeScope()
   482	
   483			check.simpleStmt(s.Init)
   484			var x operand
   485			check.expr(&x, s.Cond)
   486			if x.mode != invalid && !isBoolean(x.typ) {
   487				check.error(s.Cond.Pos(), "non-boolean condition in if statement")
   488			}
   489			check.stmt(inner, s.Body)
   490			// The parser produces a correct AST but if it was modified
   491			// elsewhere the else branch may be invalid. Check again.
   492			switch s.Else.(type) {
   493			case nil, *ast.BadStmt:
   494				// valid or error already reported
   495			case *ast.IfStmt, *ast.BlockStmt:
   496				check.stmt(inner, s.Else)
   497			default:
   498				check.error(s.Else.Pos(), "invalid else branch in if statement")
   499			}
   500	
   501		case *ast.SwitchStmt:
   502			inner |= breakOk
   503			check.openScope(s, "switch")
   504			defer check.closeScope()
   505	
   506			check.simpleStmt(s.Init)
   507			var x operand
   508			if s.Tag != nil {
   509				check.expr(&x, s.Tag)
   510				// By checking assignment of x to an invisible temporary
   511				// (as a compiler would), we get all the relevant checks.
   512				check.assignment(&x, nil, "switch expression")
   513			} else {
   514				// spec: "A missing switch expression is
   515				// equivalent to the boolean value true."
   516				x.mode = constant_
   517				x.typ = Typ[Bool]
   518				x.val = constant.MakeBool(true)
   519				x.expr = &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"}
   520			}
   521	
   522			check.multipleDefaults(s.Body.List)
   523	
   524			seen := make(valueMap) // map of seen case values to positions and types
   525			for i, c := range s.Body.List {
   526				clause, _ := c.(*ast.CaseClause)
   527				if clause == nil {
   528					check.invalidAST(c.Pos(), "incorrect expression switch case")
   529					continue
   530				}
   531				check.caseValues(&x, clause.List, seen)
   532				check.openScope(clause, "case")
   533				inner := inner
   534				if i+1 < len(s.Body.List) {
   535					inner |= fallthroughOk
   536				} else {
   537					inner |= finalSwitchCase
   538				}
   539				check.stmtList(inner, clause.Body)
   540				check.closeScope()
   541			}
   542	
   543		case *ast.TypeSwitchStmt:
   544			inner |= breakOk
   545			check.openScope(s, "type switch")
   546			defer check.closeScope()
   547	
   548			check.simpleStmt(s.Init)
   549	
   550			// A type switch guard must be of the form:
   551			//
   552			//     TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
   553			//
   554			// The parser is checking syntactic correctness;
   555			// remaining syntactic errors are considered AST errors here.
   556			// TODO(gri) better factoring of error handling (invalid ASTs)
   557			//
   558			var lhs *ast.Ident // lhs identifier or nil
   559			var rhs ast.Expr
   560			switch guard := s.Assign.(type) {
   561			case *ast.ExprStmt:
   562				rhs = guard.X
   563			case *ast.AssignStmt:
   564				if len(guard.Lhs) != 1 || guard.Tok != token.DEFINE || len(guard.Rhs) != 1 {
   565					check.invalidAST(s.Pos(), "incorrect form of type switch guard")
   566					return
   567				}
   568	
   569				lhs, _ = guard.Lhs[0].(*ast.Ident)
   570				if lhs == nil {
   571					check.invalidAST(s.Pos(), "incorrect form of type switch guard")
   572					return
   573				}
   574	
   575				if lhs.Name == "_" {
   576					// _ := x.(type) is an invalid short variable declaration
   577					check.softErrorf(lhs.Pos(), "no new variable on left side of :=")
   578					lhs = nil // avoid declared but not used error below
   579				} else {
   580					check.recordDef(lhs, nil) // lhs variable is implicitly declared in each cause clause
   581				}
   582	
   583				rhs = guard.Rhs[0]
   584	
   585			default:
   586				check.invalidAST(s.Pos(), "incorrect form of type switch guard")
   587				return
   588			}
   589	
   590			// rhs must be of the form: expr.(type) and expr must be an interface
   591			expr, _ := rhs.(*ast.TypeAssertExpr)
   592			if expr == nil || expr.Type != nil {
   593				check.invalidAST(s.Pos(), "incorrect form of type switch guard")
   594				return
   595			}
   596			var x operand
   597			check.expr(&x, expr.X)
   598			if x.mode == invalid {
   599				return
   600			}
   601			xtyp, _ := x.typ.Underlying().(*Interface)
   602			if xtyp == nil {
   603				check.errorf(x.pos(), "%s is not an interface", &x)
   604				return
   605			}
   606	
   607			check.multipleDefaults(s.Body.List)
   608	
   609			var lhsVars []*Var               // list of implicitly declared lhs variables
   610			seen := make(map[Type]token.Pos) // map of seen types to positions
   611			for _, s := range s.Body.List {
   612				clause, _ := s.(*ast.CaseClause)
   613				if clause == nil {
   614					check.invalidAST(s.Pos(), "incorrect type switch case")
   615					continue
   616				}
   617				// Check each type in this type switch case.
   618				T := check.caseTypes(&x, xtyp, clause.List, seen)
   619				check.openScope(clause, "case")
   620				// If lhs exists, declare a corresponding variable in the case-local scope.
   621				if lhs != nil {
   622					// spec: "The TypeSwitchGuard may include a short variable declaration.
   623					// When that form is used, the variable is declared at the beginning of
   624					// the implicit block in each clause. In clauses with a case listing
   625					// exactly one type, the variable has that type; otherwise, the variable
   626					// has the type of the expression in the TypeSwitchGuard."
   627					if len(clause.List) != 1 || T == nil {
   628						T = x.typ
   629					}
   630					obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, T)
   631					scopePos := clause.Pos() + token.Pos(len("default")) // for default clause (len(List) == 0)
   632					if n := len(clause.List); n > 0 {
   633						scopePos = clause.List[n-1].End()
   634					}
   635					check.declare(check.scope, nil, obj, scopePos)
   636					check.recordImplicit(clause, obj)
   637					// For the "declared but not used" error, all lhs variables act as
   638					// one; i.e., if any one of them is 'used', all of them are 'used'.
   639					// Collect them for later analysis.
   640					lhsVars = append(lhsVars, obj)
   641				}
   642				check.stmtList(inner, clause.Body)
   643				check.closeScope()
   644			}
   645	
   646			// If lhs exists, we must have at least one lhs variable that was used.
   647			if lhs != nil {
   648				var used bool
   649				for _, v := range lhsVars {
   650					if v.used {
   651						used = true
   652					}
   653					v.used = true // avoid usage error when checking entire function
   654				}
   655				if !used {
   656					check.softErrorf(lhs.Pos(), "%s declared but not used", lhs.Name)
   657				}
   658			}
   659	
   660		case *ast.SelectStmt:
   661			inner |= breakOk
   662	
   663			check.multipleDefaults(s.Body.List)
   664	
   665			for _, s := range s.Body.List {
   666				clause, _ := s.(*ast.CommClause)
   667				if clause == nil {
   668					continue // error reported before
   669				}
   670	
   671				// clause.Comm must be a SendStmt, RecvStmt, or default case
   672				valid := false
   673				var rhs ast.Expr // rhs of RecvStmt, or nil
   674				switch s := clause.Comm.(type) {
   675				case nil, *ast.SendStmt:
   676					valid = true
   677				case *ast.AssignStmt:
   678					if len(s.Rhs) == 1 {
   679						rhs = s.Rhs[0]
   680					}
   681				case *ast.ExprStmt:
   682					rhs = s.X
   683				}
   684	
   685				// if present, rhs must be a receive operation
   686				if rhs != nil {
   687					if x, _ := unparen(rhs).(*ast.UnaryExpr); x != nil && x.Op == token.ARROW {
   688						valid = true
   689					}
   690				}
   691	
   692				if !valid {
   693					check.error(clause.Comm.Pos(), "select case must be send or receive (possibly with assignment)")
   694					continue
   695				}
   696	
   697				check.openScope(s, "case")
   698				if clause.Comm != nil {
   699					check.stmt(inner, clause.Comm)
   700				}
   701				check.stmtList(inner, clause.Body)
   702				check.closeScope()
   703			}
   704	
   705		case *ast.ForStmt:
   706			inner |= breakOk | continueOk
   707			check.openScope(s, "for")
   708			defer check.closeScope()
   709	
   710			check.simpleStmt(s.Init)
   711			if s.Cond != nil {
   712				var x operand
   713				check.expr(&x, s.Cond)
   714				if x.mode != invalid && !isBoolean(x.typ) {
   715					check.error(s.Cond.Pos(), "non-boolean condition in for statement")
   716				}
   717			}
   718			check.simpleStmt(s.Post)
   719			// spec: "The init statement may be a short variable
   720			// declaration, but the post statement must not."
   721			if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
   722				check.softErrorf(s.Pos(), "cannot declare in post statement")
   723				check.use(s.Lhs...) // avoid follow-up errors
   724			}
   725			check.stmt(inner, s.Body)
   726	
   727		case *ast.RangeStmt:
   728			inner |= breakOk | continueOk
   729			check.openScope(s, "for")
   730			defer check.closeScope()
   731	
   732			// check expression to iterate over
   733			var x operand
   734			check.expr(&x, s.X)
   735	
   736			// determine key/value types
   737			var key, val Type
   738			if x.mode != invalid {
   739				switch typ := x.typ.Underlying().(type) {
   740				case *Basic:
   741					if isString(typ) {
   742						key = Typ[Int]
   743						val = universeRune // use 'rune' name
   744					}
   745				case *Array:
   746					key = Typ[Int]
   747					val = typ.elem
   748				case *Slice:
   749					key = Typ[Int]
   750					val = typ.elem
   751				case *Pointer:
   752					if typ, _ := typ.base.Underlying().(*Array); typ != nil {
   753						key = Typ[Int]
   754						val = typ.elem
   755					}
   756				case *Map:
   757					key = typ.key
   758					val = typ.elem
   759				case *Chan:
   760					key = typ.elem
   761					val = Typ[Invalid]
   762					if typ.dir == SendOnly {
   763						check.errorf(x.pos(), "cannot range over send-only channel %s", &x)
   764						// ok to continue
   765					}
   766					if s.Value != nil {
   767						check.errorf(s.Value.Pos(), "iteration over %s permits only one iteration variable", &x)
   768						// ok to continue
   769					}
   770				}
   771			}
   772	
   773			if key == nil {
   774				check.errorf(x.pos(), "cannot range over %s", &x)
   775				// ok to continue
   776			}
   777	
   778			// check assignment to/declaration of iteration variables
   779			// (irregular assignment, cannot easily map to existing assignment checks)
   780	
   781			// lhs expressions and initialization value (rhs) types
   782			lhs := [2]ast.Expr{s.Key, s.Value}
   783			rhs := [2]Type{key, val} // key, val may be nil
   784	
   785			if s.Tok == token.DEFINE {
   786				// short variable declaration; variable scope starts after the range clause
   787				// (the for loop opens a new scope, so variables on the lhs never redeclare
   788				// previously declared variables)
   789				var vars []*Var
   790				for i, lhs := range lhs {
   791					if lhs == nil {
   792						continue
   793					}
   794	
   795					// determine lhs variable
   796					var obj *Var
   797					if ident, _ := lhs.(*ast.Ident); ident != nil {
   798						// declare new variable
   799						name := ident.Name
   800						obj = NewVar(ident.Pos(), check.pkg, name, nil)
   801						check.recordDef(ident, obj)
   802						// _ variables don't count as new variables
   803						if name != "_" {
   804							vars = append(vars, obj)
   805						}
   806					} else {
   807						check.errorf(lhs.Pos(), "cannot declare %s", lhs)
   808						obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
   809					}
   810	
   811					// initialize lhs variable
   812					if typ := rhs[i]; typ != nil {
   813						x.mode = value
   814						x.expr = lhs // we don't have a better rhs expression to use here
   815						x.typ = typ
   816						check.initVar(obj, &x, "range clause")
   817					} else {
   818						obj.typ = Typ[Invalid]
   819						obj.used = true // don't complain about unused variable
   820					}
   821				}
   822	
   823				// declare variables
   824				if len(vars) > 0 {
   825					scopePos := s.X.End()
   826					for _, obj := range vars {
   827						// spec: "The scope of a constant or variable identifier declared inside
   828						// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
   829						// for short variable declarations) and ends at the end of the innermost
   830						// containing block."
   831						check.declare(check.scope, nil /* recordDef already called */, obj, scopePos)
   832					}
   833				} else {
   834					check.error(s.TokPos, "no new variables on left side of :=")
   835				}
   836			} else {
   837				// ordinary assignment
   838				for i, lhs := range lhs {
   839					if lhs == nil {
   840						continue
   841					}
   842					if typ := rhs[i]; typ != nil {
   843						x.mode = value
   844						x.expr = lhs // we don't have a better rhs expression to use here
   845						x.typ = typ
   846						check.assignVar(lhs, &x)
   847					}
   848				}
   849			}
   850	
   851			check.stmt(inner, s.Body)
   852	
   853		default:
   854			check.error(s.Pos(), "invalid statement")
   855		}
   856	}
   857	

View as plain text