// Copyright 2021 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.

package parser

import (
	
	
	
	
)

const debugResolve = false

// resolveFile walks the given file to resolve identifiers within the file
// scope, updating ast.Ident.Obj fields with declaration information.
//
// If declErr is non-nil, it is used to report declaration errors during
// resolution. tok is used to format position in error messages.
func resolveFile( *ast.File,  *token.File,  func(token.Pos, string)) {
	 := ast.NewScope(nil)
	 := &resolver{
		handle:   ,
		declErr:  ,
		topScope: ,
		pkgScope: ,
		depth:    1,
	}

	for ,  := range .Decls {
		ast.Walk(, )
	}

	.closeScope()
	assert(.topScope == nil, "unbalanced scopes")
	assert(.labelScope == nil, "unbalanced label scopes")

	// resolve global identifiers within the same file
	 := 0
	for ,  := range .unresolved {
		// i <= index for current ident
		assert(.Obj == unresolved, "object already resolved")
		.Obj = .pkgScope.Lookup(.Name) // also removes unresolved sentinel
		if .Obj == nil {
			.unresolved[] = 
			++
		} else if debugResolve {
			 := .Obj.Decl.(interface{ () token.Pos }).()
			.trace("resolved %s@%v to package object %v", .Name, .Pos(), )
		}
	}
	.Scope = .pkgScope
	.Unresolved = .unresolved[0:]
}

const maxScopeDepth int = 1e3

type resolver struct {
	handle  *token.File
	declErr func(token.Pos, string)

	// Ordinary identifier scopes
	pkgScope   *ast.Scope   // pkgScope.Outer == nil
	topScope   *ast.Scope   // top-most scope; may be pkgScope
	unresolved []*ast.Ident // unresolved identifiers
	depth      int          // scope depth

	// Label scopes
	// (maintained by open/close LabelScope)
	labelScope  *ast.Scope     // label scope for current function
	targetStack [][]*ast.Ident // stack of unresolved labels
}

func ( *resolver) ( string,  ...any) {
	fmt.Println(strings.Repeat(". ", .depth) + .sprintf(, ...))
}

func ( *resolver) ( string,  ...any) string {
	for ,  := range  {
		switch arg := .(type) {
		case token.Pos:
			[] = .handle.Position()
		}
	}
	return fmt.Sprintf(, ...)
}

func ( *resolver) ( token.Pos) {
	.depth++
	if .depth > maxScopeDepth {
		panic(bailout{pos: , msg: "exceeded max scope depth during object resolution"})
	}
	if debugResolve {
		.trace("opening scope @%v", )
	}
	.topScope = ast.NewScope(.topScope)
}

func ( *resolver) () {
	.depth--
	if debugResolve {
		.trace("closing scope")
	}
	.topScope = .topScope.Outer
}

func ( *resolver) () {
	.labelScope = ast.NewScope(.labelScope)
	.targetStack = append(.targetStack, nil)
}

func ( *resolver) () {
	// resolve labels
	 := len(.targetStack) - 1
	 := .labelScope
	for ,  := range .targetStack[] {
		.Obj = .Lookup(.Name)
		if .Obj == nil && .declErr != nil {
			.declErr(.Pos(), fmt.Sprintf("label %s undefined", .Name))
		}
	}
	// pop label scope
	.targetStack = .targetStack[0:]
	.labelScope = .labelScope.Outer
}

func ( *resolver) (,  any,  *ast.Scope,  ast.ObjKind,  ...*ast.Ident) {
	for ,  := range  {
		if .Obj != nil {
			panic(fmt.Sprintf("%v: identifier %s already declared or resolved", .Pos(), .Name))
		}
		 := ast.NewObj(, .Name)
		// remember the corresponding declaration for redeclaration
		// errors and global variable resolution/typechecking phase
		.Decl = 
		.Data = 
		// Identifiers (for receiver type parameters) are written to the scope, but
		// never set as the resolved object. See go.dev/issue/50956.
		if ,  := .(*ast.Ident); ! {
			.Obj = 
		}
		if .Name != "_" {
			if debugResolve {
				.trace("declaring %s@%v", .Name, .Pos())
			}
			if  := .Insert();  != nil && .declErr != nil {
				 := ""
				if  := .Pos(); .IsValid() {
					 = .sprintf("\n\tprevious declaration at %v", )
				}
				.declErr(.Pos(), fmt.Sprintf("%s redeclared in this block%s", .Name, ))
			}
		}
	}
}

func ( *resolver) ( *ast.AssignStmt) {
	// Go spec: A short variable declaration may redeclare variables
	// provided they were originally declared in the same block with
	// the same type, and at least one of the non-blank variables is new.
	 := 0 // number of new variables
	for ,  := range .Lhs {
		if ,  := .(*ast.Ident);  {
			assert(.Obj == nil, "identifier already declared or resolved")
			 := ast.NewObj(ast.Var, .Name)
			// remember corresponding assignment for other tools
			.Decl = 
			.Obj = 
			if .Name != "_" {
				if debugResolve {
					.trace("declaring %s@%v", .Name, .Pos())
				}
				if  := .topScope.Insert();  != nil {
					.Obj =  // redeclaration
				} else {
					++ // new declaration
				}
			}
		}
	}
	if  == 0 && .declErr != nil {
		.declErr(.Lhs[0].Pos(), "no new variables on left side of :=")
	}
}

// The unresolved object is a sentinel to mark identifiers that have been added
// to the list of unresolved identifiers. The sentinel is only used for verifying
// internal consistency.
var unresolved = new(ast.Object)

// If x is an identifier, resolve attempts to resolve x by looking up
// the object it denotes. If no object is found and collectUnresolved is
// set, x is marked as unresolved and collected in the list of unresolved
// identifiers.
func ( *resolver) ( *ast.Ident,  bool) {
	if .Obj != nil {
		panic(.sprintf("%v: identifier %s already declared or resolved", .Pos(), .Name))
	}
	// '_' should never refer to existing declarations, because it has special
	// handling in the spec.
	if .Name == "_" {
		return
	}
	for  := .topScope;  != nil;  = .Outer {
		if  := .Lookup(.Name);  != nil {
			if debugResolve {
				.trace("resolved %v:%s to %v", .Pos(), .Name, )
			}
			assert(.Name != "", "obj with no name")
			// Identifiers (for receiver type parameters) are written to the scope,
			// but never set as the resolved object. See go.dev/issue/50956.
			if ,  := .Decl.(*ast.Ident); ! {
				.Obj = 
			}
			return
		}
	}
	// all local scopes are known, so any unresolved identifier
	// must be found either in the file scope, package scope
	// (perhaps in another file), or universe scope --- collect
	// them so that they can be resolved later
	if  {
		.Obj = unresolved
		.unresolved = append(.unresolved, )
	}
}

func ( *resolver) ( []ast.Expr) {
	for ,  := range  {
		ast.Walk(, )
	}
}

func ( *resolver) ( []ast.Expr) {
	for ,  := range  {
		 := ast.Unparen()
		if ,  := .(*ast.Ident); ! &&  != nil {
			ast.Walk(, )
		}
	}
}

func ( *resolver) ( []ast.Stmt) {
	for ,  := range  {
		ast.Walk(, )
	}
}

func ( *resolver) ( ast.Node) ast.Visitor {
	if debugResolve &&  != nil {
		.trace("node %T@%v", , .Pos())
	}

	switch n := .(type) {

	// Expressions.
	case *ast.Ident:
		.resolve(, true)

	case *ast.FuncLit:
		.openScope(.Pos())
		defer .closeScope()
		.walkFuncType(.Type)
		.walkBody(.Body)

	case *ast.SelectorExpr:
		ast.Walk(, .X)
		// Note: don't try to resolve n.Sel, as we don't support qualified
		// resolution.

	case *ast.StructType:
		.openScope(.Pos())
		defer .closeScope()
		.walkFieldList(.Fields, ast.Var)

	case *ast.FuncType:
		.openScope(.Pos())
		defer .closeScope()
		.walkFuncType()

	case *ast.CompositeLit:
		if .Type != nil {
			ast.Walk(, .Type)
		}
		for ,  := range .Elts {
			if ,  := .(*ast.KeyValueExpr);  != nil {
				// See go.dev/issue/45160: try to resolve composite lit keys, but don't
				// collect them as unresolved if resolution failed. This replicates
				// existing behavior when resolving during parsing.
				if ,  := .Key.(*ast.Ident);  != nil {
					.resolve(, false)
				} else {
					ast.Walk(, .Key)
				}
				ast.Walk(, .Value)
			} else {
				ast.Walk(, )
			}
		}

	case *ast.InterfaceType:
		.openScope(.Pos())
		defer .closeScope()
		.walkFieldList(.Methods, ast.Fun)

	// Statements
	case *ast.LabeledStmt:
		.declare(, nil, .labelScope, ast.Lbl, .Label)
		ast.Walk(, .Stmt)

	case *ast.AssignStmt:
		.walkExprs(.Rhs)
		if .Tok == token.DEFINE {
			.shortVarDecl()
		} else {
			.walkExprs(.Lhs)
		}

	case *ast.BranchStmt:
		// add to list of unresolved targets
		if .Tok != token.FALLTHROUGH && .Label != nil {
			 := len(.targetStack) - 1
			.targetStack[] = append(.targetStack[], .Label)
		}

	case *ast.BlockStmt:
		.openScope(.Pos())
		defer .closeScope()
		.walkStmts(.List)

	case *ast.IfStmt:
		.openScope(.Pos())
		defer .closeScope()
		if .Init != nil {
			ast.Walk(, .Init)
		}
		ast.Walk(, .Cond)
		ast.Walk(, .Body)
		if .Else != nil {
			ast.Walk(, .Else)
		}

	case *ast.CaseClause:
		.walkExprs(.List)
		.openScope(.Pos())
		defer .closeScope()
		.walkStmts(.Body)

	case *ast.SwitchStmt:
		.openScope(.Pos())
		defer .closeScope()
		if .Init != nil {
			ast.Walk(, .Init)
		}
		if .Tag != nil {
			// The scope below reproduces some unnecessary behavior of the parser,
			// opening an extra scope in case this is a type switch. It's not needed
			// for expression switches.
			// TODO: remove this once we've matched the parser resolution exactly.
			if .Init != nil {
				.openScope(.Tag.Pos())
				defer .closeScope()
			}
			ast.Walk(, .Tag)
		}
		if .Body != nil {
			.walkStmts(.Body.List)
		}

	case *ast.TypeSwitchStmt:
		if .Init != nil {
			.openScope(.Pos())
			defer .closeScope()
			ast.Walk(, .Init)
		}
		.openScope(.Assign.Pos())
		defer .closeScope()
		ast.Walk(, .Assign)
		// s.Body consists only of case clauses, so does not get its own
		// scope.
		if .Body != nil {
			.walkStmts(.Body.List)
		}

	case *ast.CommClause:
		.openScope(.Pos())
		defer .closeScope()
		if .Comm != nil {
			ast.Walk(, .Comm)
		}
		.walkStmts(.Body)

	case *ast.SelectStmt:
		// as for switch statements, select statement bodies don't get their own
		// scope.
		if .Body != nil {
			.walkStmts(.Body.List)
		}

	case *ast.ForStmt:
		.openScope(.Pos())
		defer .closeScope()
		if .Init != nil {
			ast.Walk(, .Init)
		}
		if .Cond != nil {
			ast.Walk(, .Cond)
		}
		if .Post != nil {
			ast.Walk(, .Post)
		}
		ast.Walk(, .Body)

	case *ast.RangeStmt:
		.openScope(.Pos())
		defer .closeScope()
		ast.Walk(, .X)
		var  []ast.Expr
		if .Key != nil {
			 = append(, .Key)
		}
		if .Value != nil {
			 = append(, .Value)
		}
		if len() > 0 {
			if .Tok == token.DEFINE {
				// Note: we can't exactly match the behavior of object resolution
				// during the parsing pass here, as it uses the position of the RANGE
				// token for the RHS OpPos. That information is not contained within
				// the AST.
				 := &ast.AssignStmt{
					Lhs:    ,
					Tok:    token.DEFINE,
					TokPos: .TokPos,
					Rhs:    []ast.Expr{&ast.UnaryExpr{Op: token.RANGE, X: .X}},
				}
				// TODO(rFindley): this walkLHS reproduced the parser resolution, but
				// is it necessary? By comparison, for a normal AssignStmt we don't
				// walk the LHS in case there is an invalid identifier list.
				.walkLHS()
				.shortVarDecl()
			} else {
				.walkExprs()
			}
		}
		ast.Walk(, .Body)

	// Declarations
	case *ast.GenDecl:
		switch .Tok {
		case token.CONST, token.VAR:
			for ,  := range .Specs {
				 := .(*ast.ValueSpec)
				 := ast.Con
				if .Tok == token.VAR {
					 = ast.Var
				}
				.walkExprs(.Values)
				if .Type != nil {
					ast.Walk(, .Type)
				}
				.declare(, , .topScope, , .Names...)
			}
		case token.TYPE:
			for ,  := range .Specs {
				 := .(*ast.TypeSpec)
				// Go spec: The scope of a type identifier declared inside a function begins
				// at the identifier in the TypeSpec and ends at the end of the innermost
				// containing block.
				.declare(, nil, .topScope, ast.Typ, .Name)
				if .TypeParams != nil {
					.openScope(.Pos())
					defer .closeScope()
					.walkTParams(.TypeParams)
				}
				ast.Walk(, .Type)
			}
		}

	case *ast.FuncDecl:
		// Open the function scope.
		.openScope(.Pos())
		defer .closeScope()

		.walkRecv(.Recv)

		// Type parameters are walked normally: they can reference each other, and
		// can be referenced by normal parameters.
		if .Type.TypeParams != nil {
			.walkTParams(.Type.TypeParams)
			// TODO(rFindley): need to address receiver type parameters.
		}

		// Resolve and declare parameters in a specific order to get duplicate
		// declaration errors in the correct location.
		.resolveList(.Type.Params)
		.resolveList(.Type.Results)
		.declareList(.Recv, ast.Var)
		.declareList(.Type.Params, ast.Var)
		.declareList(.Type.Results, ast.Var)

		.walkBody(.Body)
		if .Recv == nil && .Name.Name != "init" {
			.declare(, nil, .pkgScope, ast.Fun, .Name)
		}

	default:
		return 
	}

	return nil
}

func ( *resolver) ( *ast.FuncType) {
	// typ.TypeParams must be walked separately for FuncDecls.
	.resolveList(.Params)
	.resolveList(.Results)
	.declareList(.Params, ast.Var)
	.declareList(.Results, ast.Var)
}

func ( *resolver) ( *ast.FieldList) {
	if  == nil {
		return
	}
	for ,  := range .List {
		if .Type != nil {
			ast.Walk(, .Type)
		}
	}
}

func ( *resolver) ( *ast.FieldList,  ast.ObjKind) {
	if  == nil {
		return
	}
	for ,  := range .List {
		.declare(, nil, .topScope, , .Names...)
	}
}

func ( *resolver) ( *ast.FieldList) {
	// If our receiver has receiver type parameters, we must declare them before
	// trying to resolve the rest of the receiver, and avoid re-resolving the
	// type parameter identifiers.
	if  == nil || len(.List) == 0 {
		return // nothing to do
	}
	 := .List[0].Type
	if ,  := .(*ast.StarExpr);  {
		 = .X
	}

	var  []ast.Expr // exprs to declare
	var  []ast.Expr // exprs to resolve
	switch typ := .(type) {
	case *ast.IndexExpr:
		 = []ast.Expr{.Index}
		 = append(, .X)
	case *ast.IndexListExpr:
		 = .Indices
		 = append(, .X)
	default:
		 = append(, )
	}
	for ,  := range  {
		if ,  := .(*ast.Ident);  != nil {
			.declare(, nil, .topScope, ast.Typ, )
		} else {
			// The receiver type parameter expression is invalid, but try to resolve
			// it anyway for consistency.
			 = append(, )
		}
	}
	for ,  := range  {
		if  != nil {
			ast.Walk(, )
		}
	}
	// The receiver is invalid, but try to resolve it anyway for consistency.
	for ,  := range .List[1:] {
		if .Type != nil {
			ast.Walk(, .Type)
		}
	}
}

func ( *resolver) ( *ast.FieldList,  ast.ObjKind) {
	if  == nil {
		return
	}
	.resolveList()
	.declareList(, )
}

// walkTParams is like walkFieldList, but declares type parameters eagerly so
// that they may be resolved in the constraint expressions held in the field
// Type.
func ( *resolver) ( *ast.FieldList) {
	.declareList(, ast.Typ)
	.resolveList()
}

func ( *resolver) ( *ast.BlockStmt) {
	if  == nil {
		return
	}
	.openLabelScope()
	defer .closeLabelScope()
	.walkStmts(.List)
}