]> 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                 case []*TypeParam:
128                         var buf bytes.Buffer
129                         buf.WriteByte('[')
130                         for i, x := range a {
131                                 if i > 0 {
132                                         buf.WriteString(", ")
133                                 }
134                                 buf.WriteString(typeString(x, qf, debug)) // use typeString so we get subscripts when debugging
135                         }
136                         buf.WriteByte(']')
137                         arg = buf.String()
138                 }
139                 args[i] = arg
140         }
141         return fmt.Sprintf(format, args...)
142 }
143
144 func (check *Checker) qualifier(pkg *Package) string {
145         // Qualify the package unless it's the package being type-checked.
146         if pkg != check.pkg {
147                 if check.pkgPathMap == nil {
148                         check.pkgPathMap = make(map[string]map[string]bool)
149                         check.seenPkgMap = make(map[*Package]bool)
150                         check.markImports(check.pkg)
151                 }
152                 // If the same package name was used by multiple packages, display the full path.
153                 if len(check.pkgPathMap[pkg.name]) > 1 {
154                         return strconv.Quote(pkg.path)
155                 }
156                 return pkg.name
157         }
158         return ""
159 }
160
161 // markImports recursively walks pkg and its imports, to record unique import
162 // paths in pkgPathMap.
163 func (check *Checker) markImports(pkg *Package) {
164         if check.seenPkgMap[pkg] {
165                 return
166         }
167         check.seenPkgMap[pkg] = true
168
169         forName, ok := check.pkgPathMap[pkg.name]
170         if !ok {
171                 forName = make(map[string]bool)
172                 check.pkgPathMap[pkg.name] = forName
173         }
174         forName[pkg.path] = true
175
176         for _, imp := range pkg.imports {
177                 check.markImports(imp)
178         }
179 }
180
181 // check may be nil.
182 func (check *Checker) sprintf(format string, args ...interface{}) string {
183         var qf Qualifier
184         if check != nil {
185                 qf = check.qualifier
186         }
187         return sprintf(qf, false, format, args...)
188 }
189
190 func (check *Checker) report(err *error_) {
191         if err.empty() {
192                 panic("no error to report")
193         }
194         check.err(err.pos(), err.msg(check.qualifier), err.soft)
195 }
196
197 func (check *Checker) trace(pos syntax.Pos, format string, args ...interface{}) {
198         fmt.Printf("%s:\t%s%s\n",
199                 pos,
200                 strings.Repeat(".  ", check.indent),
201                 sprintf(check.qualifier, true, format, args...),
202         )
203 }
204
205 // dump is only needed for debugging
206 func (check *Checker) dump(format string, args ...interface{}) {
207         fmt.Println(sprintf(check.qualifier, true, format, args...))
208 }
209
210 func (check *Checker) err(at poser, msg string, soft bool) {
211         // Cheap trick: Don't report errors with messages containing
212         // "invalid operand" or "invalid type" as those tend to be
213         // follow-on errors which don't add useful information. Only
214         // exclude them if these strings are not at the beginning,
215         // and only if we have at least one error already reported.
216         if check.firstErr != nil && (strings.Index(msg, "invalid operand") > 0 || strings.Index(msg, "invalid type") > 0) {
217                 return
218         }
219
220         pos := posFor(at)
221
222         // If we are encountering an error while evaluating an inherited
223         // constant initialization expression, pos is the position of in
224         // the original expression, and not of the currently declared
225         // constant identifier. Use the provided errpos instead.
226         // TODO(gri) We may also want to augment the error message and
227         // refer to the position (pos) in the original expression.
228         if check.errpos.IsKnown() {
229                 assert(check.iota != nil)
230                 pos = check.errpos
231         }
232
233         err := Error{pos, stripAnnotations(msg), msg, soft}
234         if check.firstErr == nil {
235                 check.firstErr = err
236         }
237
238         if check.conf.Trace {
239                 check.trace(pos, "ERROR: %s", msg)
240         }
241
242         f := check.conf.Error
243         if f == nil {
244                 panic(bailout{}) // report only first error
245         }
246         f(err)
247 }
248
249 const (
250         invalidAST = "invalid AST: "
251         invalidArg = "invalid argument: "
252         invalidOp  = "invalid operation: "
253 )
254
255 type poser interface {
256         Pos() syntax.Pos
257 }
258
259 func (check *Checker) error(at poser, msg string) {
260         check.err(at, msg, false)
261 }
262
263 func (check *Checker) errorf(at poser, format string, args ...interface{}) {
264         check.err(at, check.sprintf(format, args...), false)
265 }
266
267 func (check *Checker) softErrorf(at poser, format string, args ...interface{}) {
268         check.err(at, check.sprintf(format, args...), true)
269 }
270
271 func (check *Checker) versionErrorf(at poser, goVersion string, format string, args ...interface{}) {
272         msg := check.sprintf(format, args...)
273         if check.conf.CompilerErrorMessages {
274                 msg = fmt.Sprintf("%s requires %s or later (-lang was set to %s; check go.mod)", msg, goVersion, check.conf.GoVersion)
275         } else {
276                 msg = fmt.Sprintf("%s requires %s or later", msg, goVersion)
277         }
278         check.err(at, msg, true)
279 }
280
281 // posFor reports the left (= start) position of at.
282 func posFor(at poser) syntax.Pos {
283         switch x := at.(type) {
284         case *operand:
285                 if x.expr != nil {
286                         return syntax.StartPos(x.expr)
287                 }
288         case syntax.Node:
289                 return syntax.StartPos(x)
290         }
291         return at.Pos()
292 }
293
294 // stripAnnotations removes internal (type) annotations from s.
295 func stripAnnotations(s string) string {
296         // Would like to use strings.Builder but it's not available in Go 1.4.
297         var b bytes.Buffer
298         for _, r := range s {
299                 // strip #'s and subscript digits
300                 if r < '₀' || '₀'+10 <= r { // '₀' == U+2080
301                         b.WriteRune(r)
302                 }
303         }
304         if b.Len() < len(s) {
305                 return b.String()
306         }
307         return s
308 }