Source file
src/go/types/scope.go
1
2
3
4
5
6
7
8
9
10 package types
11
12 import (
13 "fmt"
14 "go/token"
15 "io"
16 "iter"
17 "slices"
18 "strings"
19 "sync"
20 "sync/atomic"
21 )
22
23
24
25
26
27 type Scope struct {
28 parent *Scope
29 children []*Scope
30 number int
31 objects map[string]Object
32 pos, end token.Pos
33 comment string
34 isFunc bool
35 sortedNames atomic.Pointer[[]string]
36 }
37
38
39
40 func NewScope(parent *Scope, pos, end token.Pos, comment string) *Scope {
41 s := &Scope{parent: parent, pos: pos, end: end, comment: comment}
42
43 if parent != nil && parent != Universe {
44 parent.children = append(parent.children, s)
45 s.number = len(parent.children)
46 }
47 return s
48 }
49
50
51 func (s *Scope) Parent() *Scope { return s.parent }
52
53
54 func (s *Scope) Len() int { return len(s.objects) }
55
56
57
58 func (s *Scope) Names() []string {
59
60
61 ptr := s.sortedNames.Load()
62 if ptr == nil {
63
64 names := make([]string, len(s.objects))
65 i := 0
66 for name := range s.objects {
67 names[i] = name
68 i++
69 }
70 slices.Sort(names)
71 ptr = &names
72
73
74 s.sortedNames.CompareAndSwap(nil, &names)
75 }
76 return *ptr
77 }
78
79
80 func (s *Scope) NumChildren() int { return len(s.children) }
81
82
83 func (s *Scope) Child(i int) *Scope { return s.children[i] }
84
85
86
87 func (s *Scope) Lookup(name string) Object { return resolve(name, s.objects[name]) }
88
89
90
91
92
93
94
95
96 func (s *Scope) Objects() iter.Seq[Object] {
97 return func(yield func(obj Object) bool) {
98 names := s.Names()
99 for _, name := range names {
100 if !yield(s.Lookup(name)) {
101 break
102 }
103 }
104 }
105 }
106
107
108
109
110 func (s *Scope) lookupIgnoringCase(name string, exported bool) []Object {
111 var matches []Object
112 for _, n := range s.Names() {
113 if (!exported || isExported(n)) && strings.EqualFold(n, name) {
114 matches = append(matches, s.Lookup(n))
115 }
116 }
117 return matches
118 }
119
120
121
122
123
124
125 func (s *Scope) Insert(obj Object) Object {
126 name := obj.Name()
127 if alt := s.Lookup(name); alt != nil {
128 return alt
129 }
130 s.insert(name, obj)
131
132
133
134
135
136 if obj.Parent() == nil {
137 obj.setParent(s)
138 }
139 return nil
140 }
141
142
143
144
145
146
147
148
149 func (s *Scope) _InsertLazy(name string, resolve func() Object) bool {
150 if s.objects[name] != nil {
151 return false
152 }
153 s.insert(name, &lazyObject{parent: s, resolve: resolve})
154 return true
155 }
156
157 func (s *Scope) insert(name string, obj Object) {
158 if s.objects == nil {
159 s.objects = make(map[string]Object)
160 }
161 s.sortedNames.Store(nil)
162 s.objects[name] = obj
163 }
164
165
166
167
168
169
170 func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) {
171 const ind = ". "
172 indn := strings.Repeat(ind, n)
173
174 fmt.Fprintf(w, "%s%s scope %p {\n", indn, s.comment, s)
175
176 indn1 := indn + ind
177 for _, name := range s.Names() {
178 fmt.Fprintf(w, "%s%s\n", indn1, s.Lookup(name))
179 }
180
181 if recurse {
182 for _, s := range s.children {
183 s.WriteTo(w, n+1, recurse)
184 }
185 }
186
187 fmt.Fprintf(w, "%s}\n", indn)
188 }
189
190
191 func (s *Scope) String() string {
192 var buf strings.Builder
193 s.WriteTo(&buf, 0, false)
194 return buf.String()
195 }
196
197
198
199 type lazyObject struct {
200 parent *Scope
201 resolve func() Object
202 obj Object
203 once sync.Once
204 }
205
206
207
208 func resolve(name string, obj Object) Object {
209 if lazy, ok := obj.(*lazyObject); ok {
210 lazy.once.Do(func() {
211 obj := lazy.resolve()
212
213 if _, ok := obj.(*lazyObject); ok {
214 panic("recursive lazy object")
215 }
216 if obj.Name() != name {
217 panic("lazy object has unexpected name")
218 }
219
220 if obj.Parent() == nil {
221 obj.setParent(lazy.parent)
222 }
223 lazy.obj = obj
224 })
225
226 obj = lazy.obj
227 }
228 return obj
229 }
230
231
232
233 func (*lazyObject) Parent() *Scope { panic("unreachable") }
234 func (*lazyObject) Pos() token.Pos { panic("unreachable") }
235 func (*lazyObject) Pkg() *Package { panic("unreachable") }
236 func (*lazyObject) Name() string { panic("unreachable") }
237 func (*lazyObject) Type() Type { panic("unreachable") }
238 func (*lazyObject) Exported() bool { panic("unreachable") }
239 func (*lazyObject) Id() string { panic("unreachable") }
240 func (*lazyObject) String() string { panic("unreachable") }
241 func (*lazyObject) order() uint32 { panic("unreachable") }
242 func (*lazyObject) setType(Type) { panic("unreachable") }
243 func (*lazyObject) setOrder(uint32) { panic("unreachable") }
244 func (*lazyObject) setParent(*Scope) { panic("unreachable") }
245 func (*lazyObject) sameId(*Package, string, bool) bool { panic("unreachable") }
246 func (*lazyObject) scopePos() token.Pos { panic("unreachable") }
247 func (*lazyObject) setScopePos(token.Pos) { panic("unreachable") }
248
View as plain text