// Copyright 2012 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 statements.

package types

import (
	
	
	
	
)

func ( *Checker) ( *declInfo,  string,  *Signature,  *ast.BlockStmt,  constant.Value) {
	if trace {
		.trace(.Pos(), "--- %s: %s", , )
		defer func() {
			.trace(.End(), "--- <end>")
		}()
	}

	// set function scope extent
	.scope.pos = .Pos()
	.scope.end = .End()

	// save/restore current context and setup function context
	// (and use 0 indentation at function start)
	defer func( context,  int) {
		.context = 
		.indent = 
	}(.context, .indent)
	.context = context{
		decl:  ,
		scope: .scope,
		iota:  ,
		sig:   ,
	}
	.indent = 0

	.stmtList(0, .List)

	if .hasLabel {
		.labels()
	}

	if .results.Len() > 0 && !.isTerminating(, "") {
		.error(atPos(.Rbrace), _MissingReturn, "missing return")
	}

	// spec: "Implementation restriction: A compiler may make it illegal to
	// declare a variable inside a function body if the variable is never used."
	.usage(.scope)
}

func ( *Checker) ( *Scope) {
	var  []*Var
	for ,  := range .elems {
		if ,  := .(*Var);  != nil && !.used {
			 = append(, )
		}
	}
	sort.Slice(, func(,  int) bool {
		return [].pos < [].pos
	})
	for ,  := range  {
		.softErrorf(, _UnusedVar, "%s declared but not used", .name)
	}

	for ,  := range .children {
		// Don't go inside function literal scopes a second time;
		// they are handled explicitly by funcBody.
		if !.isFunc {
			.()
		}
	}
}

// stmtContext is a bitset describing which
// control-flow statements are permissible,
// and provides additional context information
// for better error messages.
type stmtContext uint

const (
	// permissible control-flow statements
	breakOk stmtContext = 1 << iota
	continueOk
	fallthroughOk

	// additional context information
	finalSwitchCase
)

func ( *Checker) ( ast.Stmt) {
	if  != nil {
		.stmt(0, )
	}
}

func trimTrailingEmptyStmts( []ast.Stmt) []ast.Stmt {
	for  := len();  > 0; -- {
		if ,  := [-1].(*ast.EmptyStmt); ! {
			return [:]
		}
	}
	return nil
}

func ( *Checker) ( stmtContext,  []ast.Stmt) {
	 := &fallthroughOk != 0
	 :=  &^ fallthroughOk
	 = trimTrailingEmptyStmts() // trailing empty statements are "invisible" to fallthrough analysis
	for ,  := range  {
		 := 
		if  && +1 == len() {
			 |= fallthroughOk
		}
		.stmt(, )
	}
}

func ( *Checker) ( []ast.Stmt) {
	var  ast.Stmt
	for ,  := range  {
		var  ast.Stmt
		switch c := .(type) {
		case *ast.CaseClause:
			if len(.List) == 0 {
				 = 
			}
		case *ast.CommClause:
			if .Comm == nil {
				 = 
			}
		default:
			.invalidAST(, "case/communication clause expected")
		}
		if  != nil {
			if  != nil {
				.errorf(, _DuplicateDefault, "multiple defaults (first at %s)", .fset.Position(.Pos()))
			} else {
				 = 
			}
		}
	}
}

func ( *Checker) ( ast.Stmt,  string) {
	 := NewScope(.scope, .Pos(), .End(), )
	.recordScope(, )
	.scope = 
}

func ( *Checker) () {
	.scope = .scope.Parent()
}

func assignOp( token.Token) token.Token {
	// token_test.go verifies the token ordering this function relies on
	if token.ADD_ASSIGN <=  &&  <= token.AND_NOT_ASSIGN {
		return  + (token.ADD - token.ADD_ASSIGN)
	}
	return token.ILLEGAL
}

func ( *Checker) ( string,  *ast.CallExpr) {
	var  operand
	var  string
	var  errorCode
	switch .rawExpr(&, , nil) {
	case conversion:
		 = "requires function call, not conversion"
		 = _InvalidDefer
		if  == "go" {
			 = _InvalidGo
		}
	case expression:
		 = "discards result of"
		 = _UnusedResults
	case statement:
		return
	default:
		unreachable()
	}
	.errorf(&, , "%s %s %s", , , &)
}

// goVal returns the Go value for val, or nil.
func goVal( constant.Value) interface{} {
	// val should exist, but be conservative and check
	if  == nil {
		return nil
	}
	// Match implementation restriction of other compilers.
	// gc only checks duplicates for integer, floating-point
	// and string values, so only create Go values for these
	// types.
	switch .Kind() {
	case constant.Int:
		if ,  := constant.Int64Val();  {
			return 
		}
		if ,  := constant.Uint64Val();  {
			return 
		}
	case constant.Float:
		if ,  := constant.Float64Val();  {
			return 
		}
	case constant.String:
		return constant.StringVal()
	}
	return nil
}

// A valueMap maps a case value (of a basic Go type) to a list of positions
// where the same case value appeared, together with the corresponding case
// types.
// Since two case values may have the same "underlying" value but different
// types we need to also check the value's types (e.g., byte(1) vs myByte(1))
// when the switch expression is of interface type.
type (
	valueMap  map[interface{}][]valueType // underlying Go value -> valueType
	valueType struct {
		pos token.Pos
		typ Type
	}
)

func ( *Checker) ( *operand,  []ast.Expr,  valueMap) {
:
	for ,  := range  {
		var  operand
		.expr(&, )
		if .mode == invalid || .mode == invalid {
			continue 
		}
		.convertUntyped(&, .typ)
		if .mode == invalid {
			continue 
		}
		// Order matters: By comparing v against x, error positions are at the case values.
		 :=  // keep original v unchanged
		.comparison(&, , token.EQL)
		if .mode == invalid {
			continue 
		}
		if .mode != constant_ {
			continue  // we're done
		}
		// look for duplicate values
		if  := goVal(.val);  != nil {
			// look for duplicate types for a given value
			// (quadratic algorithm, but these lists tend to be very short)
			for ,  := range [] {
				if .identical(.typ, .typ) {
					.errorf(&, _DuplicateCase, "duplicate case %s in expression switch", &)
					.error(atPos(.pos), _DuplicateCase, "\tprevious case") // secondary error, \t indented
					continue 
				}
			}
			[] = append([], valueType{.Pos(), .typ})
		}
	}
}

func ( *Checker) ( *operand,  *Interface,  []ast.Expr,  map[Type]ast.Expr) ( Type) {
:
	for ,  := range  {
		 = .typOrNil()
		if  == Typ[Invalid] {
			continue 
		}
		// look for duplicate types
		// (quadratic algorithm, but type switches tend to be reasonably small)
		for ,  := range  {
			if  == nil &&  == nil ||  != nil &&  != nil && .identical(, ) {
				// talk about "case" rather than "type" because of nil case
				 := "nil"
				if  != nil {
					 = .String()
				}
				.errorf(, _DuplicateCase, "duplicate case %s in type switch", )
				.error(, _DuplicateCase, "\tprevious case") // secondary error, \t indented
				continue 
			}
		}
		[] = 
		if  != nil {
			.typeAssertion(, , , )
		}
	}
	return
}

// stmt typechecks statement s.
func ( *Checker) ( stmtContext,  ast.Stmt) {
	// statements must end with the same top scope as they started with
	if debug {
		defer func( *Scope) {
			// don't check if code is panicking
			if  := recover();  != nil {
				panic()
			}
			assert( == .scope)
		}(.scope)
	}

	// process collected function literals before scope changes
	defer .processDelayed(len(.delayed))

	 :=  &^ (fallthroughOk | finalSwitchCase)
	switch s := .(type) {
	case *ast.BadStmt, *ast.EmptyStmt:
		// ignore

	case *ast.DeclStmt:
		.declStmt(.Decl)

	case *ast.LabeledStmt:
		.hasLabel = true
		.(, .Stmt)

	case *ast.ExprStmt:
		// spec: "With the exception of specific built-in functions,
		// function and method calls and receive operations can appear
		// in statement context. Such statements may be parenthesized."
		var  operand
		 := .rawExpr(&, .X, nil)
		var  string
		var  errorCode
		switch .mode {
		default:
			if  == statement {
				return
			}
			 = "is not used"
			 = _UnusedExpr
		case builtin:
			 = "must be called"
			 = _UncalledBuiltin
		case typexpr:
			 = "is not an expression"
			 = _NotAnExpr
		}
		.errorf(&, , "%s %s", &, )

	case *ast.SendStmt:
		var ,  operand
		.expr(&, .Chan)
		.expr(&, .Value)
		if .mode == invalid || .mode == invalid {
			return
		}

		,  := .typ.Underlying().(*Chan)
		if ! {
			.invalidOp(inNode(, .Arrow), _InvalidSend, "cannot send to non-chan type %s", .typ)
			return
		}

		if .dir == RecvOnly {
			.invalidOp(inNode(, .Arrow), _InvalidSend, "cannot send to receive-only type %s", )
			return
		}

		.assignment(&, .elem, "send")

	case *ast.IncDecStmt:
		var  token.Token
		switch .Tok {
		case token.INC:
			 = token.ADD
		case token.DEC:
			 = token.SUB
		default:
			.invalidAST(inNode(, .TokPos), "unknown inc/dec operation %s", .Tok)
			return
		}

		var  operand
		.expr(&, .X)
		if .mode == invalid {
			return
		}
		if !isNumeric(.typ) {
			.invalidOp(.X, _NonNumericIncDec, "%s%s (non-numeric type %s)", .X, .Tok, .typ)
			return
		}

		 := &ast.BasicLit{ValuePos: .X.Pos(), Kind: token.INT, Value: "1"} // use x's position
		.binary(&, nil, .X, , , .TokPos)
		if .mode == invalid {
			return
		}
		.assignVar(.X, &)

	case *ast.AssignStmt:
		switch .Tok {
		case token.ASSIGN, token.DEFINE:
			if len(.Lhs) == 0 {
				.invalidAST(, "missing lhs in assignment")
				return
			}
			if .Tok == token.DEFINE {
				.shortVarDecl(inNode(, .TokPos), .Lhs, .Rhs)
			} else {
				// regular assignment
				.assignVars(.Lhs, .Rhs)
			}

		default:
			// assignment operations
			if len(.Lhs) != 1 || len(.Rhs) != 1 {
				.errorf(inNode(, .TokPos), _MultiValAssignOp, "assignment operation %s requires single-valued expressions", .Tok)
				return
			}
			 := assignOp(.Tok)
			if  == token.ILLEGAL {
				.invalidAST(atPos(.TokPos), "unknown assignment operation %s", .Tok)
				return
			}
			var  operand
			.binary(&, nil, .Lhs[0], .Rhs[0], , .TokPos)
			if .mode == invalid {
				return
			}
			.assignVar(.Lhs[0], &)
		}

	case *ast.GoStmt:
		.suspendedCall("go", .Call)

	case *ast.DeferStmt:
		.suspendedCall("defer", .Call)

	case *ast.ReturnStmt:
		 := .sig.results
		if .Len() > 0 {
			// function returns results
			// (if one, say the first, result parameter is named, all of them are named)
			if len(.Results) == 0 && .vars[0].name != "" {
				// spec: "Implementation restriction: A compiler may disallow an empty expression
				// list in a "return" statement if a different entity (constant, type, or variable)
				// with the same name as a result parameter is in scope at the place of the return."
				for ,  := range .vars {
					if  := .lookup(.name);  != nil &&  !=  {
						.errorf(, _OutOfScopeResult, "result parameter %s not in scope at return", .name)
						.errorf(, _OutOfScopeResult, "\tinner declaration of %s", )
						// ok to continue
					}
				}
			} else {
				// return has results or result parameters are unnamed
				.initVars(.vars, .Results, .Return)
			}
		} else if len(.Results) > 0 {
			.error(.Results[0], _WrongResultCount, "no result values expected")
			.use(.Results...)
		}

	case *ast.BranchStmt:
		if .Label != nil {
			.hasLabel = true
			return // checked in 2nd pass (check.labels)
		}
		switch .Tok {
		case token.BREAK:
			if &breakOk == 0 {
				.error(, _MisplacedBreak, "break not in for, switch, or select statement")
			}
		case token.CONTINUE:
			if &continueOk == 0 {
				.error(, _MisplacedContinue, "continue not in for statement")
			}
		case token.FALLTHROUGH:
			if &fallthroughOk == 0 {
				 := "fallthrough statement out of place"
				 := _MisplacedFallthrough
				if &finalSwitchCase != 0 {
					 = "cannot fallthrough final case in switch"
				}
				.error(, , )
			}
		default:
			.invalidAST(, "branch statement: %s", .Tok)
		}

	case *ast.BlockStmt:
		.openScope(, "block")
		defer .closeScope()

		.stmtList(, .List)

	case *ast.IfStmt:
		.openScope(, "if")
		defer .closeScope()

		.simpleStmt(.Init)
		var  operand
		.expr(&, .Cond)
		if .mode != invalid && !isBoolean(.typ) {
			.error(.Cond, _InvalidCond, "non-boolean condition in if statement")
		}
		.(, .Body)
		// The parser produces a correct AST but if it was modified
		// elsewhere the else branch may be invalid. Check again.
		switch .Else.(type) {
		case nil, *ast.BadStmt:
			// valid or error already reported
		case *ast.IfStmt, *ast.BlockStmt:
			.(, .Else)
		default:
			.invalidAST(.Else, "invalid else branch in if statement")
		}

	case *ast.SwitchStmt:
		 |= breakOk
		.openScope(, "switch")
		defer .closeScope()

		.simpleStmt(.Init)
		var  operand
		if .Tag != nil {
			.expr(&, .Tag)
			// By checking assignment of x to an invisible temporary
			// (as a compiler would), we get all the relevant checks.
			.assignment(&, nil, "switch expression")
			if .mode != invalid && !Comparable(.typ) && !hasNil(.typ) {
				.errorf(&, _InvalidExprSwitch, "cannot switch on %s (%s is not comparable)", &, .typ)
				.mode = invalid
			}
		} else {
			// spec: "A missing switch expression is
			// equivalent to the boolean value true."
			.mode = constant_
			.typ = Typ[Bool]
			.val = constant.MakeBool(true)
			.expr = &ast.Ident{NamePos: .Body.Lbrace, Name: "true"}
		}

		.multipleDefaults(.Body.List)

		 := make(valueMap) // map of seen case values to positions and types
		for ,  := range .Body.List {
			,  := .(*ast.CaseClause)
			if  == nil {
				.invalidAST(, "incorrect expression switch case")
				continue
			}
			.caseValues(&, .List, )
			.openScope(, "case")
			 := 
			if +1 < len(.Body.List) {
				 |= fallthroughOk
			} else {
				 |= finalSwitchCase
			}
			.stmtList(, .Body)
			.closeScope()
		}

	case *ast.TypeSwitchStmt:
		 |= breakOk
		.openScope(, "type switch")
		defer .closeScope()

		.simpleStmt(.Init)

		// A type switch guard must be of the form:
		//
		//     TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
		//
		// The parser is checking syntactic correctness;
		// remaining syntactic errors are considered AST errors here.
		// TODO(gri) better factoring of error handling (invalid ASTs)
		//
		var  *ast.Ident // lhs identifier or nil
		var  ast.Expr
		switch guard := .Assign.(type) {
		case *ast.ExprStmt:
			 = .X
		case *ast.AssignStmt:
			if len(.Lhs) != 1 || .Tok != token.DEFINE || len(.Rhs) != 1 {
				.invalidAST(, "incorrect form of type switch guard")
				return
			}

			, _ = .Lhs[0].(*ast.Ident)
			if  == nil {
				.invalidAST(, "incorrect form of type switch guard")
				return
			}

			if .Name == "_" {
				// _ := x.(type) is an invalid short variable declaration
				.softErrorf(, _NoNewVar, "no new variable on left side of :=")
				 = nil // avoid declared but not used error below
			} else {
				.recordDef(, nil) // lhs variable is implicitly declared in each cause clause
			}

			 = .Rhs[0]

		default:
			.invalidAST(, "incorrect form of type switch guard")
			return
		}

		// rhs must be of the form: expr.(type) and expr must be an interface
		,  := .(*ast.TypeAssertExpr)
		if  == nil || .Type != nil {
			.invalidAST(, "incorrect form of type switch guard")
			return
		}
		var  operand
		.expr(&, .X)
		if .mode == invalid {
			return
		}
		,  := .typ.Underlying().(*Interface)
		if  == nil {
			.errorf(&, _InvalidTypeSwitch, "%s is not an interface", &)
			return
		}

		.multipleDefaults(.Body.List)

		var  []*Var              // list of implicitly declared lhs variables
		 := make(map[Type]ast.Expr) // map of seen types to positions
		for ,  := range .Body.List {
			,  := .(*ast.CaseClause)
			if  == nil {
				.invalidAST(, "incorrect type switch case")
				continue
			}
			// Check each type in this type switch case.
			 := .caseTypes(&, , .List, )
			.openScope(, "case")
			// If lhs exists, declare a corresponding variable in the case-local scope.
			if  != nil {
				// spec: "The TypeSwitchGuard may include a short variable declaration.
				// When that form is used, the variable is declared at the beginning of
				// the implicit block in each clause. In clauses with a case listing
				// exactly one type, the variable has that type; otherwise, the variable
				// has the type of the expression in the TypeSwitchGuard."
				if len(.List) != 1 ||  == nil {
					 = .typ
				}
				 := NewVar(.Pos(), .pkg, .Name, )
				 := .Pos() + token.Pos(len("default")) // for default clause (len(List) == 0)
				if  := len(.List);  > 0 {
					 = .List[-1].End()
				}
				.declare(.scope, nil, , )
				.recordImplicit(, )
				// For the "declared but not used" error, all lhs variables act as
				// one; i.e., if any one of them is 'used', all of them are 'used'.
				// Collect them for later analysis.
				 = append(, )
			}
			.stmtList(, .Body)
			.closeScope()
		}

		// If lhs exists, we must have at least one lhs variable that was used.
		if  != nil {
			var  bool
			for ,  := range  {
				if .used {
					 = true
				}
				.used = true // avoid usage error when checking entire function
			}
			if ! {
				.softErrorf(, _UnusedVar, "%s declared but not used", .Name)
			}
		}

	case *ast.SelectStmt:
		 |= breakOk

		.multipleDefaults(.Body.List)

		for ,  := range .Body.List {
			,  := .(*ast.CommClause)
			if  == nil {
				continue // error reported before
			}

			// clause.Comm must be a SendStmt, RecvStmt, or default case
			 := false
			var  ast.Expr // rhs of RecvStmt, or nil
			switch s := .Comm.(type) {
			case nil, *ast.SendStmt:
				 = true
			case *ast.AssignStmt:
				if len(.Rhs) == 1 {
					 = .Rhs[0]
				}
			case *ast.ExprStmt:
				 = .X
			}

			// if present, rhs must be a receive operation
			if  != nil {
				if ,  := unparen().(*ast.UnaryExpr);  != nil && .Op == token.ARROW {
					 = true
				}
			}

			if ! {
				.error(.Comm, _InvalidSelectCase, "select case must be send or receive (possibly with assignment)")
				continue
			}

			.openScope(, "case")
			if .Comm != nil {
				.(, .Comm)
			}
			.stmtList(, .Body)
			.closeScope()
		}

	case *ast.ForStmt:
		 |= breakOk | continueOk
		.openScope(, "for")
		defer .closeScope()

		.simpleStmt(.Init)
		if .Cond != nil {
			var  operand
			.expr(&, .Cond)
			if .mode != invalid && !isBoolean(.typ) {
				.error(.Cond, _InvalidCond, "non-boolean condition in for statement")
			}
		}
		.simpleStmt(.Post)
		// spec: "The init statement may be a short variable
		// declaration, but the post statement must not."
		if ,  := .Post.(*ast.AssignStmt);  != nil && .Tok == token.DEFINE {
			.softErrorf(, _InvalidPostDecl, "cannot declare in post statement")
			// Don't call useLHS here because we want to use the lhs in
			// this erroneous statement so that we don't get errors about
			// these lhs variables being declared but not used.
			.use(.Lhs...) // avoid follow-up errors
		}
		.(, .Body)

	case *ast.RangeStmt:
		 |= breakOk | continueOk
		.openScope(, "for")
		defer .closeScope()

		// check expression to iterate over
		var  operand
		.expr(&, .X)

		// determine key/value types
		var ,  Type
		if .mode != invalid {
			switch typ := .typ.Underlying().(type) {
			case *Basic:
				if isString() {
					 = Typ[Int]
					 = universeRune // use 'rune' name
				}
			case *Array:
				 = Typ[Int]
				 = .elem
			case *Slice:
				 = Typ[Int]
				 = .elem
			case *Pointer:
				if ,  := .base.Underlying().(*Array);  != nil {
					 = Typ[Int]
					 = .elem
				}
			case *Map:
				 = .key
				 = .elem
			case *Chan:
				 = .elem
				 = Typ[Invalid]
				if .dir == SendOnly {
					.errorf(&, _InvalidChanRange, "cannot range over send-only channel %s", &)
					// ok to continue
				}
				if .Value != nil {
					.errorf(atPos(.Value.Pos()), _InvalidIterVar, "iteration over %s permits only one iteration variable", &)
					// ok to continue
				}
			}
		}

		if  == nil {
			.errorf(&, _InvalidRangeExpr, "cannot range over %s", &)
			// ok to continue
		}

		// 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{.Key, .Value}
		 := [2]Type{, } // key, val may be nil

		if .Tok == token.DEFINE {
			// short variable declaration; variable scope starts after the range clause
			// (the for loop opens a new scope, so variables on the lhs never redeclare
			// previously declared variables)
			var  []*Var
			for ,  := range  {
				if  == nil {
					continue
				}

				// determine lhs variable
				var  *Var
				if ,  := .(*ast.Ident);  != nil {
					// declare new variable
					 := .Name
					 = NewVar(.Pos(), .pkg, , nil)
					.recordDef(, )
					// _ variables don't count as new variables
					if  != "_" {
						 = append(, )
					}
				} else {
					.invalidAST(, "cannot declare %s", )
					 = NewVar(.Pos(), .pkg, "_", nil) // dummy variable
				}

				// initialize lhs variable
				if  := [];  != nil {
					.mode = value
					.expr =  // we don't have a better rhs expression to use here
					.typ = 
					.initVar(, &, "range clause")
				} else {
					.typ = Typ[Invalid]
					.used = true // don't complain about unused variable
				}
			}

			// declare variables
			if len() > 0 {
				 := .X.End()
				for ,  := range  {
					// spec: "The scope of a constant or variable identifier declared inside
					// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
					// for short variable declarations) and ends at the end of the innermost
					// containing block."
					.declare(.scope, nil /* recordDef already called */, , )
				}
			} else {
				.error(inNode(, .TokPos), _NoNewVar, "no new variables on left side of :=")
			}
		} else {
			// ordinary assignment
			for ,  := range  {
				if  == nil {
					continue
				}
				if  := [];  != nil {
					.mode = value
					.expr =  // we don't have a better rhs expression to use here
					.typ = 
					.assignVar(, &)
				}
			}
		}

		.(, .Body)

	default:
		.invalidAST(, "invalid statement")
	}
}