1// Copyright 2017 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
5package types
6
7import "cmd/internal/src"
8
9// Declaration stack & operations
10
11var blockgen int32 = 1 // max block number
12var Block int32        // current block number
13
14// A dsym stores a symbol's shadowed declaration so that it can be
15// restored once the block scope ends.
16type dsym struct {
17	sym        *Sym // sym == nil indicates stack mark
18	def        *Node
19	block      int32
20	lastlineno src.XPos // last declaration for diagnostic
21}
22
23// dclstack maintains a stack of shadowed symbol declarations so that
24// Popdcl can restore their declarations when a block scope ends.
25var dclstack []dsym
26
27// Pushdcl pushes the current declaration for symbol s (if any) so that
28// it can be shadowed by a new declaration within a nested block scope.
29func Pushdcl(s *Sym) {
30	dclstack = append(dclstack, dsym{
31		sym:        s,
32		def:        s.Def,
33		block:      s.Block,
34		lastlineno: s.Lastlineno,
35	})
36}
37
38// Popdcl pops the innermost block scope and restores all symbol declarations
39// to their previous state.
40func Popdcl() {
41	for i := len(dclstack); i > 0; i-- {
42		d := &dclstack[i-1]
43		s := d.sym
44		if s == nil {
45			// pop stack mark
46			Block = d.block
47			dclstack = dclstack[:i-1]
48			return
49		}
50
51		s.Def = d.def
52		s.Block = d.block
53		s.Lastlineno = d.lastlineno
54
55		// Clear dead pointer fields.
56		d.sym = nil
57		d.def = nil
58	}
59	Fatalf("popdcl: no stack mark")
60}
61
62// Markdcl records the start of a new block scope for declarations.
63func Markdcl() {
64	dclstack = append(dclstack, dsym{
65		sym:   nil, // stack mark
66		block: Block,
67	})
68	blockgen++
69	Block = blockgen
70}
71
72func IsDclstackValid() bool {
73	for _, d := range dclstack {
74		if d.sym == nil {
75			return false
76		}
77	}
78	return true
79}
80
81// PkgDef returns the definition associated with s at package scope.
82func (s *Sym) PkgDef() *Node {
83	return *s.pkgDefPtr()
84}
85
86// SetPkgDef sets the definition associated with s at package scope.
87func (s *Sym) SetPkgDef(n *Node) {
88	*s.pkgDefPtr() = n
89}
90
91func (s *Sym) pkgDefPtr() **Node {
92	// Look for outermost saved declaration, which must be the
93	// package scope definition, if present.
94	for _, d := range dclstack {
95		if s == d.sym {
96			return &d.def
97		}
98	}
99
100	// Otherwise, the declaration hasn't been shadowed within a
101	// function scope.
102	return &s.Def
103}
104