]> 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 // check may be nil.
171 func (check *Checker) sprintf(format string, args ...interface{}) string {
172         var qf Qualifier
173         if check != nil {
174                 qf = check.qualifier
175         }
176         return sprintf(qf, false, format, args...)
177 }
178
179 func (check *Checker) report(err *error_) {
180         if err.empty() {
181                 panic("no error to report")
182         }
183         check.err(err.pos(), err.msg(check.qualifier), err.soft)
184 }
185
186 func (check *Checker) trace(pos syntax.Pos, format string, args ...interface{}) {
187         fmt.Printf("%s:\t%s%s\n",
188                 pos,
189                 strings.Repeat(".  ", check.indent),
190                 sprintf(check.qualifier, true, format, args...),
191         )
192 }
193
194 // dump is only needed for debugging
195 func (check *Checker) dump(format string, args ...interface{}) {
196         fmt.Println(sprintf(check.qualifier, true, format, args...))
197 }
198
199 func (check *Checker) err(at poser, msg string, soft bool) {
200         // Cheap trick: Don't report errors with messages containing
201         // "invalid operand" or "invalid type" as those tend to be
202         // follow-on errors which don't add useful information. Only
203         // exclude them if these strings are not at the beginning,
204         // and only if we have at least one error already reported.
205         if check.firstErr != nil && (strings.Index(msg, "invalid operand") > 0 || strings.Index(msg, "invalid type") > 0) {
206                 return
207         }
208
209         pos := posFor(at)
210
211         // If we are encountering an error while evaluating an inherited
212         // constant initialization expression, pos is the position of in
213         // the original expression, and not of the currently declared
214         // constant identifier. Use the provided errpos instead.
215         // TODO(gri) We may also want to augment the error message and
216         // refer to the position (pos) in the original expression.
217         if check.errpos.IsKnown() {
218                 assert(check.iota != nil)
219                 pos = check.errpos
220         }
221
222         err := Error{pos, stripAnnotations(msg), msg, soft}
223         if check.firstErr == nil {
224                 check.firstErr = err
225         }
226
227         if check.conf.Trace {
228                 check.trace(pos, "ERROR: %s", msg)
229         }
230
231         f := check.conf.Error
232         if f == nil {
233                 panic(bailout{}) // report only first error
234         }
235         f(err)
236 }
237
238 const (
239         invalidAST = "invalid AST: "
240         invalidArg = "invalid argument: "
241         invalidOp  = "invalid operation: "
242 )
243
244 type poser interface {
245         Pos() syntax.Pos
246 }
247
248 func (check *Checker) error(at poser, msg string) {
249         check.err(at, msg, false)
250 }
251
252 func (check *Checker) errorf(at poser, format string, args ...interface{}) {
253         check.err(at, check.sprintf(format, args...), false)
254 }
255
256 func (check *Checker) softErrorf(at poser, format string, args ...interface{}) {
257         check.err(at, check.sprintf(format, args...), true)
258 }
259
260 func (check *Checker) versionErrorf(at poser, goVersion string, format string, args ...interface{}) {
261         msg := check.sprintf(format, args...)
262         if check.conf.CompilerErrorMessages {
263                 msg = fmt.Sprintf("%s requires %s or later (-lang was set to %s; check go.mod)", msg, goVersion, check.conf.GoVersion)
264         } else {
265                 msg = fmt.Sprintf("%s requires %s or later", msg, goVersion)
266         }
267         check.err(at, msg, true)
268 }
269
270 // posFor reports the left (= start) position of at.
271 func posFor(at poser) syntax.Pos {
272         switch x := at.(type) {
273         case *operand:
274                 if x.expr != nil {
275                         return syntax.StartPos(x.expr)
276                 }
277         case syntax.Node:
278                 return syntax.StartPos(x)
279         }
280         return at.Pos()
281 }
282
283 // stripAnnotations removes internal (type) annotations from s.
284 func stripAnnotations(s string) string {
285         // Would like to use strings.Builder but it's not available in Go 1.4.
286         var b bytes.Buffer
287         for _, r := range s {
288                 // strip #'s and subscript digits
289                 if r < '₀' || '₀'+10 <= r { // '₀' == U+2080
290                         b.WriteRune(r)
291                 }
292         }
293         if b.Len() < len(s) {
294                 return b.String()
295         }
296         return s
297 }