...

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

View as plain text