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