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