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