func (check *Checker) isTerminating(s ast.Stmt, label string) bool {
	switch s := s.(type) {
	default:
		unreachable()
	case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.SendStmt,
		*ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt, *ast.DeferStmt,
		*ast.RangeStmt:
	case *ast.LabeledStmt:
		return check.isTerminating(s.Stmt, s.Label.Name)
	case *ast.ExprStmt:
		if call, _ := unparen(s.X).(*ast.CallExpr); call != nil {
			if id, _ := call.Fun.(*ast.Ident); id != nil {
				if _, obj := check.scope.LookupParent(id.Name, token.NoPos); obj != nil {
					if b, _ := obj.(*Builtin); b != nil && b.id == _Panic {
						return true
					}
				}
			}
		}
	case *ast.ReturnStmt:
		return true
	case *ast.BranchStmt:
		if s.Tok == token.GOTO || s.Tok == token.FALLTHROUGH {
			return true
		}
	case *ast.BlockStmt:
		return check.isTerminatingList(s.List, "")
	case *ast.IfStmt:
		if s.Else != nil &&
			check.isTerminating(s.Body, "") &&
			check.isTerminating(s.Else, "") {
			return true
		}
	case *ast.SwitchStmt:
		return check.isTerminatingSwitch(s.Body, label)
	case *ast.TypeSwitchStmt:
		return check.isTerminatingSwitch(s.Body, label)
	case *ast.SelectStmt:
		for _, s := range s.Body.List {
			cc := s.(*ast.CommClause)
			if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) {
				return false
			}
		}
		return true
	case *ast.ForStmt:
		if s.Cond == nil && !hasBreak(s.Body, label, true) {
			return true
		}
	}
	return false
}
isTerminating reports if s is a terminating statement.
If s is labeled, label is the label name; otherwise s
is "".
package types
import (
	"go/ast"
	"go/token"
)