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