Source file
src/go/types/errors.go
1
2
3
4
5
6
7 package types
8
9 import (
10 "bytes"
11 "errors"
12 "fmt"
13 "go/ast"
14 "go/token"
15 "strconv"
16 "strings"
17 )
18
19 func assert(p bool) {
20 if !p {
21 panic("assertion failed")
22 }
23 }
24
25 func unreachable() {
26 panic("unreachable")
27 }
28
29 func (check *Checker) qualifier(pkg *Package) string {
30
31 if pkg != check.pkg {
32 if check.pkgPathMap == nil {
33 check.pkgPathMap = make(map[string]map[string]bool)
34 check.seenPkgMap = make(map[*Package]bool)
35 check.markImports(check.pkg)
36 }
37
38 if len(check.pkgPathMap[pkg.name]) > 1 {
39 return strconv.Quote(pkg.path)
40 }
41 return pkg.name
42 }
43 return ""
44 }
45
46
47
48 func (check *Checker) markImports(pkg *Package) {
49 if check.seenPkgMap[pkg] {
50 return
51 }
52 check.seenPkgMap[pkg] = true
53
54 forName, ok := check.pkgPathMap[pkg.name]
55 if !ok {
56 forName = make(map[string]bool)
57 check.pkgPathMap[pkg.name] = forName
58 }
59 forName[pkg.path] = true
60
61 for _, imp := range pkg.imports {
62 check.markImports(imp)
63 }
64 }
65
66
67 func (check *Checker) sprintf(format string, args ...any) string {
68 var fset *token.FileSet
69 var qf Qualifier
70 if check != nil {
71 fset = check.fset
72 qf = check.qualifier
73 }
74 return sprintf(fset, qf, false, format, args...)
75 }
76
77 func sprintf(fset *token.FileSet, qf Qualifier, debug bool, format string, args ...any) string {
78 for i, arg := range args {
79 switch a := arg.(type) {
80 case nil:
81 arg = "<nil>"
82 case operand:
83 panic("got operand instead of *operand")
84 case *operand:
85 arg = operandString(a, qf)
86 case token.Pos:
87 if fset != nil {
88 arg = fset.Position(a).String()
89 }
90 case ast.Expr:
91 arg = ExprString(a)
92 case []ast.Expr:
93 var buf bytes.Buffer
94 buf.WriteByte('[')
95 writeExprList(&buf, a)
96 buf.WriteByte(']')
97 arg = buf.String()
98 case Object:
99 arg = ObjectString(a, qf)
100 case Type:
101 arg = typeString(a, qf, debug)
102 case []Type:
103 var buf bytes.Buffer
104 buf.WriteByte('[')
105 for i, x := range a {
106 if i > 0 {
107 buf.WriteString(", ")
108 }
109 buf.WriteString(typeString(x, qf, debug))
110 }
111 buf.WriteByte(']')
112 arg = buf.String()
113 case []*TypeParam:
114 var buf bytes.Buffer
115 buf.WriteByte('[')
116 for i, x := range a {
117 if i > 0 {
118 buf.WriteString(", ")
119 }
120 buf.WriteString(typeString(x, qf, debug))
121 }
122 buf.WriteByte(']')
123 arg = buf.String()
124 }
125 args[i] = arg
126 }
127 return fmt.Sprintf(format, args...)
128 }
129
130 func (check *Checker) trace(pos token.Pos, format string, args ...any) {
131 fmt.Printf("%s:\t%s%s\n",
132 check.fset.Position(pos),
133 strings.Repeat(". ", check.indent),
134 sprintf(check.fset, check.qualifier, true, format, args...),
135 )
136 }
137
138
139 func (check *Checker) dump(format string, args ...any) {
140 fmt.Println(sprintf(check.fset, check.qualifier, true, format, args...))
141 }
142
143 func (check *Checker) err(err error) {
144 if err == nil {
145 return
146 }
147 var e Error
148 isInternal := errors.As(err, &e)
149
150
151
152
153
154 isInvalidErr := isInternal && (strings.Index(e.Msg, "invalid operand") > 0 || strings.Index(e.Msg, "invalid type") > 0)
155 if check.firstErr != nil && isInvalidErr {
156 return
157 }
158
159 if isInternal {
160 e.Msg = stripAnnotations(e.Msg)
161 if check.errpos != nil {
162
163
164
165
166 span := spanOf(check.errpos)
167 e.Pos = span.pos
168 e.go116start = span.start
169 e.go116end = span.end
170 }
171 err = e
172 }
173
174 if check.firstErr == nil {
175 check.firstErr = err
176 }
177
178 if trace {
179 pos := e.Pos
180 msg := e.Msg
181 if !isInternal {
182 msg = err.Error()
183 pos = token.NoPos
184 }
185 check.trace(pos, "ERROR: %s", msg)
186 }
187
188 f := check.conf.Error
189 if f == nil {
190 panic(bailout{})
191 }
192 f(err)
193 }
194
195 func (check *Checker) newError(at positioner, code errorCode, soft bool, msg string) error {
196 span := spanOf(at)
197 return Error{
198 Fset: check.fset,
199 Pos: span.pos,
200 Msg: msg,
201 Soft: soft,
202 go116code: code,
203 go116start: span.start,
204 go116end: span.end,
205 }
206 }
207
208
209 func (check *Checker) newErrorf(at positioner, code errorCode, soft bool, format string, args ...any) error {
210 msg := check.sprintf(format, args...)
211 return check.newError(at, code, soft, msg)
212 }
213
214 func (check *Checker) error(at positioner, code errorCode, msg string) {
215 check.err(check.newError(at, code, false, msg))
216 }
217
218 func (check *Checker) errorf(at positioner, code errorCode, format string, args ...any) {
219 check.error(at, code, check.sprintf(format, args...))
220 }
221
222 func (check *Checker) softErrorf(at positioner, code errorCode, format string, args ...any) {
223 check.err(check.newErrorf(at, code, true, format, args...))
224 }
225
226 func (check *Checker) invalidAST(at positioner, format string, args ...any) {
227 check.errorf(at, 0, "invalid AST: "+format, args...)
228 }
229
230 func (check *Checker) invalidArg(at positioner, code errorCode, format string, args ...any) {
231 check.errorf(at, code, "invalid argument: "+format, args...)
232 }
233
234 func (check *Checker) invalidOp(at positioner, code errorCode, format string, args ...any) {
235 check.errorf(at, code, "invalid operation: "+format, args...)
236 }
237
238
239
240 type positioner interface {
241 Pos() token.Pos
242 }
243
244
245
246
247
248
249 type posSpan struct {
250 start, pos, end token.Pos
251 }
252
253 func (e posSpan) Pos() token.Pos {
254 return e.pos
255 }
256
257
258
259
260 func inNode(node ast.Node, pos token.Pos) posSpan {
261 start, end := node.Pos(), node.End()
262 if debug {
263 assert(start <= pos && pos < end)
264 }
265 return posSpan{start, pos, end}
266 }
267
268
269 type atPos token.Pos
270
271 func (s atPos) Pos() token.Pos {
272 return token.Pos(s)
273 }
274
275
276
277
278 func spanOf(at positioner) posSpan {
279 switch x := at.(type) {
280 case nil:
281 panic("nil positioner")
282 case posSpan:
283 return x
284 case ast.Node:
285 pos := x.Pos()
286 return posSpan{pos, pos, x.End()}
287 case *operand:
288 if x.expr != nil {
289 pos := x.Pos()
290 return posSpan{pos, pos, x.expr.End()}
291 }
292 return posSpan{token.NoPos, token.NoPos, token.NoPos}
293 default:
294 pos := at.Pos()
295 return posSpan{pos, pos, pos}
296 }
297 }
298
299
300 func stripAnnotations(s string) string {
301 var b strings.Builder
302 for _, r := range s {
303
304 if r < '₀' || '₀'+10 <= r {
305 b.WriteRune(r)
306 }
307 }
308 if b.Len() < len(s) {
309 return b.String()
310 }
311 return s
312 }
313
View as plain text