]> 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 Object:
102                         arg = ObjectString(a, qf)
103                 case Type:
104                         arg = typeString(a, qf, debug)
105                 }
106                 args[i] = arg
107         }
108         return fmt.Sprintf(format, args...)
109 }
110
111 func (check *Checker) qualifier(pkg *Package) string {
112         // Qualify the package unless it's the package being type-checked.
113         if pkg != check.pkg {
114                 if check.pkgPathMap == nil {
115                         check.pkgPathMap = make(map[string]map[string]bool)
116                         check.seenPkgMap = make(map[*Package]bool)
117                         check.markImports(check.pkg)
118                 }
119                 // If the same package name was used by multiple packages, display the full path.
120                 if len(check.pkgPathMap[pkg.name]) > 1 {
121                         return strconv.Quote(pkg.path)
122                 }
123                 return pkg.name
124         }
125         return ""
126 }
127
128 // markImports recursively walks pkg and its imports, to record unique import
129 // paths in pkgPathMap.
130 func (check *Checker) markImports(pkg *Package) {
131         if check.seenPkgMap[pkg] {
132                 return
133         }
134         check.seenPkgMap[pkg] = true
135
136         forName, ok := check.pkgPathMap[pkg.name]
137         if !ok {
138                 forName = make(map[string]bool)
139                 check.pkgPathMap[pkg.name] = forName
140         }
141         forName[pkg.path] = true
142
143         for _, imp := range pkg.imports {
144                 check.markImports(imp)
145         }
146 }
147
148 func (check *Checker) sprintf(format string, args ...interface{}) string {
149         return sprintf(check.qualifier, false, format, args...)
150 }
151
152 func (check *Checker) report(err *error_) {
153         if err.empty() {
154                 panic("no error to report")
155         }
156         check.err(err.pos(), err.msg(check.qualifier), err.soft)
157 }
158
159 func (check *Checker) trace(pos syntax.Pos, format string, args ...interface{}) {
160         fmt.Printf("%s:\t%s%s\n",
161                 pos,
162                 strings.Repeat(".  ", check.indent),
163                 sprintf(check.qualifier, true, format, args...),
164         )
165 }
166
167 // dump is only needed for debugging
168 func (check *Checker) dump(format string, args ...interface{}) {
169         fmt.Println(sprintf(check.qualifier, true, format, args...))
170 }
171
172 func (check *Checker) err(at poser, msg string, soft bool) {
173         // Cheap trick: Don't report errors with messages containing
174         // "invalid operand" or "invalid type" as those tend to be
175         // follow-on errors which don't add useful information. Only
176         // exclude them if these strings are not at the beginning,
177         // and only if we have at least one error already reported.
178         if check.firstErr != nil && (strings.Index(msg, "invalid operand") > 0 || strings.Index(msg, "invalid type") > 0) {
179                 return
180         }
181
182         pos := posFor(at)
183
184         // If we are encountering an error while evaluating an inherited
185         // constant initialization expression, pos is the position of in
186         // the original expression, and not of the currently declared
187         // constant identifier. Use the provided errpos instead.
188         // TODO(gri) We may also want to augment the error message and
189         // refer to the position (pos) in the original expression.
190         if check.errpos.IsKnown() {
191                 assert(check.iota != nil)
192                 pos = check.errpos
193         }
194
195         err := Error{pos, stripAnnotations(msg), msg, soft}
196         if check.firstErr == nil {
197                 check.firstErr = err
198         }
199
200         if check.conf.Trace {
201                 check.trace(pos, "ERROR: %s", msg)
202         }
203
204         f := check.conf.Error
205         if f == nil {
206                 panic(bailout{}) // report only first error
207         }
208         f(err)
209 }
210
211 const (
212         invalidAST = "invalid AST: "
213         invalidArg = "invalid argument: "
214         invalidOp  = "invalid operation: "
215 )
216
217 type poser interface {
218         Pos() syntax.Pos
219 }
220
221 func (check *Checker) error(at poser, msg string) {
222         check.err(at, msg, false)
223 }
224
225 func (check *Checker) errorf(at poser, format string, args ...interface{}) {
226         check.err(at, check.sprintf(format, args...), false)
227 }
228
229 func (check *Checker) softErrorf(at poser, format string, args ...interface{}) {
230         check.err(at, check.sprintf(format, args...), true)
231 }
232
233 // posFor reports the left (= start) position of at.
234 func posFor(at poser) syntax.Pos {
235         switch x := at.(type) {
236         case *operand:
237                 if x.expr != nil {
238                         return syntax.StartPos(x.expr)
239                 }
240         case syntax.Node:
241                 return syntax.StartPos(x)
242         }
243         return at.Pos()
244 }
245
246 // stripAnnotations removes internal (type) annotations from s.
247 func stripAnnotations(s string) string {
248         // Would like to use strings.Builder but it's not available in Go 1.4.
249         var b bytes.Buffer
250         for _, r := range s {
251                 // strip #'s and subscript digits
252                 if r < '₀' || '₀'+10 <= r { // '₀' == U+2080
253                         b.WriteRune(r)
254                 }
255         }
256         if b.Len() < len(s) {
257                 return b.String()
258         }
259         return s
260 }