]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/types2/errors.go
cmd/compile: handle go.mod error msg reference in noder, not type checker
[gostls13.git] / src / cmd / compile / internal / types2 / errors.go
1 // Copyright 2012 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
5 // This file implements various error reporters.
6
7 package types2
8
9 import (
10         "bytes"
11         "cmd/compile/internal/syntax"
12         "fmt"
13         "runtime"
14         "strconv"
15         "strings"
16 )
17
18 func unimplemented() {
19         panic("unimplemented")
20 }
21
22 func assert(p bool) {
23         if !p {
24                 msg := "assertion failed"
25                 // Include information about the assertion location. Due to panic recovery,
26                 // this location is otherwise buried in the middle of the panicking stack.
27                 if _, file, line, ok := runtime.Caller(1); ok {
28                         msg = fmt.Sprintf("%s:%d: %s", file, line, msg)
29                 }
30                 panic(msg)
31         }
32 }
33
34 func unreachable() {
35         panic("unreachable")
36 }
37
38 // An error_ represents a type-checking error.
39 // To report an error_, call Checker.report.
40 type error_ struct {
41         desc []errorDesc
42         code errorCode
43         soft bool // TODO(gri) eventually determine this from an error code
44 }
45
46 // An errorDesc describes part of a type-checking error.
47 type errorDesc struct {
48         pos    syntax.Pos
49         format string
50         args   []interface{}
51 }
52
53 func (err *error_) empty() bool {
54         return err.desc == nil
55 }
56
57 func (err *error_) pos() syntax.Pos {
58         if err.empty() {
59                 return nopos
60         }
61         return err.desc[0].pos
62 }
63
64 func (err *error_) msg(qf Qualifier) string {
65         if err.empty() {
66                 return "no error"
67         }
68         var buf strings.Builder
69         for i := range err.desc {
70                 p := &err.desc[i]
71                 if i > 0 {
72                         fmt.Fprint(&buf, "\n\t")
73                         if p.pos.IsKnown() {
74                                 fmt.Fprintf(&buf, "%s: ", p.pos)
75                         }
76                 }
77                 buf.WriteString(sprintf(qf, false, p.format, p.args...))
78         }
79         return buf.String()
80 }
81
82 // String is for testing.
83 func (err *error_) String() string {
84         if err.empty() {
85                 return "no error"
86         }
87         return fmt.Sprintf("%s: %s", err.pos(), err.msg(nil))
88 }
89
90 // errorf adds formatted error information to err.
91 // It may be called multiple times to provide additional information.
92 func (err *error_) errorf(at poser, format string, args ...interface{}) {
93         err.desc = append(err.desc, errorDesc{posFor(at), format, args})
94 }
95
96 func sprintf(qf Qualifier, tpSubscripts bool, format string, args ...interface{}) string {
97         for i, arg := range args {
98                 switch a := arg.(type) {
99                 case nil:
100                         arg = "<nil>"
101                 case operand:
102                         panic("got operand instead of *operand")
103                 case *operand:
104                         arg = operandString(a, qf)
105                 case syntax.Pos:
106                         arg = a.String()
107                 case syntax.Expr:
108                         arg = syntax.String(a)
109                 case []syntax.Expr:
110                         var buf strings.Builder
111                         buf.WriteByte('[')
112                         for i, x := range a {
113                                 if i > 0 {
114                                         buf.WriteString(", ")
115                                 }
116                                 buf.WriteString(syntax.String(x))
117                         }
118                         buf.WriteByte(']')
119                         arg = buf.String()
120                 case Object:
121                         arg = ObjectString(a, qf)
122                 case Type:
123                         var buf bytes.Buffer
124                         w := newTypeWriter(&buf, qf)
125                         w.tpSubscripts = tpSubscripts
126                         w.typ(a)
127                         arg = buf.String()
128                 case []Type:
129                         var buf bytes.Buffer
130                         w := newTypeWriter(&buf, qf)
131                         w.tpSubscripts = tpSubscripts
132                         buf.WriteByte('[')
133                         for i, x := range a {
134                                 if i > 0 {
135                                         buf.WriteString(", ")
136                                 }
137                                 w.typ(x)
138                         }
139                         buf.WriteByte(']')
140                         arg = buf.String()
141                 case []*TypeParam:
142                         var buf bytes.Buffer
143                         w := newTypeWriter(&buf, qf)
144                         w.tpSubscripts = tpSubscripts
145                         buf.WriteByte('[')
146                         for i, x := range a {
147                                 if i > 0 {
148                                         buf.WriteString(", ")
149                                 }
150                                 w.typ(x)
151                         }
152                         buf.WriteByte(']')
153                         arg = buf.String()
154                 }
155                 args[i] = arg
156         }
157         return fmt.Sprintf(format, args...)
158 }
159
160 func (check *Checker) qualifier(pkg *Package) string {
161         // Qualify the package unless it's the package being type-checked.
162         if pkg != check.pkg {
163                 if check.pkgPathMap == nil {
164                         check.pkgPathMap = make(map[string]map[string]bool)
165                         check.seenPkgMap = make(map[*Package]bool)
166                         check.markImports(check.pkg)
167                 }
168                 // If the same package name was used by multiple packages, display the full path.
169                 if len(check.pkgPathMap[pkg.name]) > 1 {
170                         return strconv.Quote(pkg.path)
171                 }
172                 return pkg.name
173         }
174         return ""
175 }
176
177 // markImports recursively walks pkg and its imports, to record unique import
178 // paths in pkgPathMap.
179 func (check *Checker) markImports(pkg *Package) {
180         if check.seenPkgMap[pkg] {
181                 return
182         }
183         check.seenPkgMap[pkg] = true
184
185         forName, ok := check.pkgPathMap[pkg.name]
186         if !ok {
187                 forName = make(map[string]bool)
188                 check.pkgPathMap[pkg.name] = forName
189         }
190         forName[pkg.path] = true
191
192         for _, imp := range pkg.imports {
193                 check.markImports(imp)
194         }
195 }
196
197 // check may be nil.
198 func (check *Checker) sprintf(format string, args ...interface{}) string {
199         var qf Qualifier
200         if check != nil {
201                 qf = check.qualifier
202         }
203         return sprintf(qf, false, format, args...)
204 }
205
206 func (check *Checker) report(err *error_) {
207         if err.empty() {
208                 panic("no error to report")
209         }
210         check.err(err.pos(), err.code, err.msg(check.qualifier), err.soft)
211 }
212
213 func (check *Checker) trace(pos syntax.Pos, format string, args ...interface{}) {
214         fmt.Printf("%s:\t%s%s\n",
215                 pos,
216                 strings.Repeat(".  ", check.indent),
217                 sprintf(check.qualifier, true, format, args...),
218         )
219 }
220
221 // dump is only needed for debugging
222 func (check *Checker) dump(format string, args ...interface{}) {
223         fmt.Println(sprintf(check.qualifier, true, format, args...))
224 }
225
226 func (check *Checker) err(at poser, code errorCode, msg string, soft bool) {
227         // Cheap trick: Don't report errors with messages containing
228         // "invalid operand" or "invalid type" as those tend to be
229         // follow-on errors which don't add useful information. Only
230         // exclude them if these strings are not at the beginning,
231         // and only if we have at least one error already reported.
232         if check.firstErr != nil && (strings.Index(msg, "invalid operand") > 0 || strings.Index(msg, "invalid type") > 0) {
233                 return
234         }
235
236         pos := posFor(at)
237
238         // If we are encountering an error while evaluating an inherited
239         // constant initialization expression, pos is the position of in
240         // the original expression, and not of the currently declared
241         // constant identifier. Use the provided errpos instead.
242         // TODO(gri) We may also want to augment the error message and
243         // refer to the position (pos) in the original expression.
244         if check.errpos.IsKnown() {
245                 assert(check.iota != nil)
246                 pos = check.errpos
247         }
248
249         err := Error{pos, stripAnnotations(msg), msg, soft}
250         if check.firstErr == nil {
251                 check.firstErr = err
252         }
253
254         if check.conf.Trace {
255                 check.trace(pos, "ERROR: %s", msg)
256         }
257
258         f := check.conf.Error
259         if f == nil {
260                 panic(bailout{}) // report only first error
261         }
262         f(err)
263 }
264
265 const (
266         invalidAST = "invalid AST: "
267         invalidArg = "invalid argument: "
268         invalidOp  = "invalid operation: "
269 )
270
271 type poser interface {
272         Pos() syntax.Pos
273 }
274
275 func (check *Checker) error(at poser, code errorCode, msg string) {
276         check.err(at, code, msg, false)
277 }
278
279 func (check *Checker) errorf(at poser, code errorCode, format string, args ...interface{}) {
280         check.err(at, code, check.sprintf(format, args...), false)
281 }
282
283 func (check *Checker) softErrorf(at poser, code errorCode, format string, args ...interface{}) {
284         check.err(at, code, check.sprintf(format, args...), true)
285 }
286
287 func (check *Checker) versionErrorf(at poser, goVersion string, format string, args ...interface{}) {
288         msg := check.sprintf(format, args...)
289         msg = fmt.Sprintf("%s requires %s or later", msg, goVersion)
290         check.err(at, _UnsupportedFeature, msg, true)
291 }
292
293 // posFor reports the left (= start) position of at.
294 func posFor(at poser) syntax.Pos {
295         switch x := at.(type) {
296         case *operand:
297                 if x.expr != nil {
298                         return syntax.StartPos(x.expr)
299                 }
300         case syntax.Node:
301                 return syntax.StartPos(x)
302         }
303         return at.Pos()
304 }
305
306 // stripAnnotations removes internal (type) annotations from s.
307 func stripAnnotations(s string) string {
308         var buf strings.Builder
309         for _, r := range s {
310                 // strip #'s and subscript digits
311                 if r < '₀' || '₀'+10 <= r { // '₀' == U+2080
312                         buf.WriteRune(r)
313                 }
314         }
315         if buf.Len() < len(s) {
316                 return buf.String()
317         }
318         return s
319 }