]> Cypherpunks.ru repositories - gostls13.git/blob - src/go/types/errors.go
go/types: walk all imports when determining package name ambiguity
[gostls13.git] / src / go / types / 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 types
8
9 import (
10         "errors"
11         "fmt"
12         "go/ast"
13         "go/token"
14         "strconv"
15         "strings"
16 )
17
18 func assert(p bool) {
19         if !p {
20                 panic("assertion failed")
21         }
22 }
23
24 func unreachable() {
25         panic("unreachable")
26 }
27
28 func (check *Checker) qualifier(pkg *Package) string {
29         // Qualify the package unless it's the package being type-checked.
30         if pkg != check.pkg {
31                 if check.pkgPathMap == nil {
32                         check.pkgPathMap = make(map[string]map[string]bool)
33                         check.seenPkgMap = make(map[*Package]bool)
34                         check.markImports(pkg)
35                 }
36                 // If the same package name was used by multiple packages, display the full path.
37                 if len(check.pkgPathMap[pkg.name]) > 1 {
38                         return strconv.Quote(pkg.path)
39                 }
40                 return pkg.name
41         }
42         return ""
43 }
44
45 // markImports recursively walks pkg and its imports, to record unique import
46 // paths in pkgPathMap.
47 func (check *Checker) markImports(pkg *Package) {
48         if check.seenPkgMap[pkg] {
49                 return
50         }
51         check.seenPkgMap[pkg] = true
52
53         forName, ok := check.pkgPathMap[pkg.name]
54         if !ok {
55                 forName = make(map[string]bool)
56                 check.pkgPathMap[pkg.name] = forName
57         }
58         forName[pkg.path] = true
59
60         for _, imp := range pkg.imports {
61                 check.markImports(imp)
62         }
63 }
64
65 func (check *Checker) sprintf(format string, args ...interface{}) string {
66         for i, arg := range args {
67                 switch a := arg.(type) {
68                 case nil:
69                         arg = "<nil>"
70                 case operand:
71                         panic("internal error: should always pass *operand")
72                 case *operand:
73                         arg = operandString(a, check.qualifier)
74                 case token.Pos:
75                         arg = check.fset.Position(a).String()
76                 case ast.Expr:
77                         arg = ExprString(a)
78                 case Object:
79                         arg = ObjectString(a, check.qualifier)
80                 case Type:
81                         arg = TypeString(a, check.qualifier)
82                 }
83                 args[i] = arg
84         }
85         return fmt.Sprintf(format, args...)
86 }
87
88 func (check *Checker) trace(pos token.Pos, format string, args ...interface{}) {
89         fmt.Printf("%s:\t%s%s\n",
90                 check.fset.Position(pos),
91                 strings.Repeat(".  ", check.indent),
92                 check.sprintf(format, args...),
93         )
94 }
95
96 // dump is only needed for debugging
97 func (check *Checker) dump(format string, args ...interface{}) {
98         fmt.Println(check.sprintf(format, args...))
99 }
100
101 func (check *Checker) err(err error) {
102         if err == nil {
103                 return
104         }
105         var e Error
106         isInternal := errors.As(err, &e)
107         // Cheap trick: Don't report errors with messages containing
108         // "invalid operand" or "invalid type" as those tend to be
109         // follow-on errors which don't add useful information. Only
110         // exclude them if these strings are not at the beginning,
111         // and only if we have at least one error already reported.
112         isInvalidErr := isInternal && (strings.Index(e.Msg, "invalid operand") > 0 || strings.Index(e.Msg, "invalid type") > 0)
113         if check.firstErr != nil && isInvalidErr {
114                 return
115         }
116
117         if isInternal {
118                 e.Msg = stripAnnotations(e.Msg)
119                 if check.errpos != nil {
120                         // If we have an internal error and the errpos override is set, use it to
121                         // augment our error positioning.
122                         // TODO(rFindley) we may also want to augment the error message and refer
123                         // to the position (pos) in the original expression.
124                         span := spanOf(check.errpos)
125                         e.Pos = span.pos
126                         e.go116start = span.start
127                         e.go116end = span.end
128                 }
129                 err = e
130         }
131
132         if check.firstErr == nil {
133                 check.firstErr = err
134         }
135
136         if trace {
137                 pos := e.Pos
138                 msg := e.Msg
139                 if !isInternal {
140                         msg = err.Error()
141                         pos = token.NoPos
142                 }
143                 check.trace(pos, "ERROR: %s", msg)
144         }
145
146         f := check.conf.Error
147         if f == nil {
148                 panic(bailout{}) // report only first error
149         }
150         f(err)
151 }
152
153 func (check *Checker) newError(at positioner, code errorCode, soft bool, msg string) error {
154         span := spanOf(at)
155         return Error{
156                 Fset:       check.fset,
157                 Pos:        span.pos,
158                 Msg:        msg,
159                 Soft:       soft,
160                 go116code:  code,
161                 go116start: span.start,
162                 go116end:   span.end,
163         }
164 }
165
166 // newErrorf creates a new Error, but does not handle it.
167 func (check *Checker) newErrorf(at positioner, code errorCode, soft bool, format string, args ...interface{}) error {
168         msg := check.sprintf(format, args...)
169         return check.newError(at, code, soft, msg)
170 }
171
172 func (check *Checker) error(at positioner, code errorCode, msg string) {
173         check.err(check.newError(at, code, false, msg))
174 }
175
176 func (check *Checker) errorf(at positioner, code errorCode, format string, args ...interface{}) {
177         check.error(at, code, check.sprintf(format, args...))
178 }
179
180 func (check *Checker) softErrorf(at positioner, code errorCode, format string, args ...interface{}) {
181         check.err(check.newErrorf(at, code, true, format, args...))
182 }
183
184 func (check *Checker) invalidAST(at positioner, format string, args ...interface{}) {
185         check.errorf(at, 0, "invalid AST: "+format, args...)
186 }
187
188 func (check *Checker) invalidArg(at positioner, code errorCode, format string, args ...interface{}) {
189         check.errorf(at, code, "invalid argument: "+format, args...)
190 }
191
192 func (check *Checker) invalidOp(at positioner, code errorCode, format string, args ...interface{}) {
193         check.errorf(at, code, "invalid operation: "+format, args...)
194 }
195
196 // The positioner interface is used to extract the position of type-checker
197 // errors.
198 type positioner interface {
199         Pos() token.Pos
200 }
201
202 // posSpan holds a position range along with a highlighted position within that
203 // range. This is used for positioning errors, with pos by convention being the
204 // first position in the source where the error is known to exist, and start
205 // and end defining the full span of syntax being considered when the error was
206 // detected. Invariant: start <= pos < end || start == pos == end.
207 type posSpan struct {
208         start, pos, end token.Pos
209 }
210
211 func (e posSpan) Pos() token.Pos {
212         return e.pos
213 }
214
215 // inNode creates a posSpan for the given node.
216 // Invariant: node.Pos() <= pos < node.End() (node.End() is the position of the
217 // first byte after node within the source).
218 func inNode(node ast.Node, pos token.Pos) posSpan {
219         start, end := node.Pos(), node.End()
220         if debug {
221                 assert(start <= pos && pos < end)
222         }
223         return posSpan{start, pos, end}
224 }
225
226 // atPos wraps a token.Pos to implement the positioner interface.
227 type atPos token.Pos
228
229 func (s atPos) Pos() token.Pos {
230         return token.Pos(s)
231 }
232
233 // spanOf extracts an error span from the given positioner. By default this is
234 // the trivial span starting and ending at pos, but this span is expanded when
235 // the argument naturally corresponds to a span of source code.
236 func spanOf(at positioner) posSpan {
237         switch x := at.(type) {
238         case nil:
239                 panic("internal error: nil")
240         case posSpan:
241                 return x
242         case ast.Node:
243                 pos := x.Pos()
244                 return posSpan{pos, pos, x.End()}
245         case *operand:
246                 if x.expr != nil {
247                         pos := x.Pos()
248                         return posSpan{pos, pos, x.expr.End()}
249                 }
250                 return posSpan{token.NoPos, token.NoPos, token.NoPos}
251         default:
252                 pos := at.Pos()
253                 return posSpan{pos, pos, pos}
254         }
255 }
256
257 // stripAnnotations removes internal (type) annotations from s.
258 func stripAnnotations(s string) string {
259         var b strings.Builder
260         for _, r := range s {
261                 // strip #'s and subscript digits
262                 if r != instanceMarker && !('₀' <= r && r < '₀'+10) { // '₀' == U+2080
263                         b.WriteRune(r)
264                 }
265         }
266         if b.Len() < len(s) {
267                 return b.String()
268         }
269         return s
270 }