1
0
mirror of https://github.com/golang/go synced 2024-11-22 14:15:05 -07:00

[dev.regabi] cmd/compile: clean up error API

Prepare for factoring the error API out of this package by
cleaning it up. The doc comments use the intended new names,
which will be introduced in the next CL.

Change-Id: Ie4c8d4262422da32a9a9f750fda42c225b6b42a8
Reviewed-on: https://go-review.googlesource.com/c/go/+/272248
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Russ Cox 2020-11-16 11:08:38 -05:00
parent 5fd949e4bd
commit 357c576878
14 changed files with 283 additions and 254 deletions

1
src/_rex.20201123151057 Normal file
View File

@ -0,0 +1 @@

View File

@ -19,9 +19,6 @@ var externdcl []*Node
func testdclstack() {
if !types.IsDclstackValid() {
if nerrors != 0 {
errorexit()
}
Fatalf("mark left on the dclstack")
}
}

View File

@ -102,16 +102,6 @@ var pragcgobuf [][]string
var outfile string
var linkobj string
// nerrors is the number of compiler errors reported
// since the last call to saveerrors.
var nerrors int
// nsavederrors is the total number of compiler errors
// reported before the last call to saveerrors.
var nsavederrors int
var nsyntaxerrors int
var decldepth int32
var nolocalimports bool

View File

@ -104,9 +104,7 @@ func initOrder(l []*Node) []*Node {
// confused us and there might not be
// a loop. Let the user fix those
// first.
if nerrors > 0 {
errorexit()
}
ExitIfErrors()
findInitLoopAndExit(firstLHS(n), new([]*Node))
Fatalf("initialization unfinished, but failed to identify loop")

View File

@ -12,10 +12,6 @@ import (
"strings"
)
// lineno is the source position at the start of the most recently lexed token.
// TODO(gri) rename and eventually remove
var lineno src.XPos
func makePos(base *src.PosBase, line, col uint) src.XPos {
return Ctxt.PosTable.XPos(src.MakePos(base, line, col))
}

View File

@ -119,7 +119,7 @@ func usage() {
}
func hidePanic() {
if Debug_panic == 0 && nsavederrors+nerrors > 0 {
if Debug_panic == 0 && Errors() > 0 {
// If we've already complained about things
// in the program, don't bother complaining
// about a panic too; let the user clean up
@ -567,7 +567,6 @@ func Main(archInit func(*Arch)) {
initUniverse()
dclcontext = PEXTERN
nerrors = 0
autogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
@ -625,10 +624,10 @@ func Main(archInit func(*Arch)) {
if n.Op == ODCLFUNC {
Curfn = n
decldepth = 1
saveerrors()
errorsBefore := Errors()
typecheckslice(Curfn.Nbody.Slice(), ctxStmt)
checkreturn(Curfn)
if nerrors != 0 {
if Errors() > errorsBefore {
Curfn.Nbody.Set(nil) // type errors; do not compile
}
// Now that we've checked whether n terminates,
@ -641,11 +640,9 @@ func Main(archInit func(*Arch)) {
// check past phase 9 isn't sufficient, as we may exit with other errors
// before then, thus skipping map key errors.
checkMapKeys()
timings.AddEvent(fcount, "funcs")
ExitIfErrors()
if nsavederrors+nerrors != 0 {
errorexit()
}
timings.AddEvent(fcount, "funcs")
fninit(xtop)
@ -660,12 +657,8 @@ func Main(archInit func(*Arch)) {
}
}
capturevarscomplete = true
Curfn = nil
if nsavederrors+nerrors != 0 {
errorexit()
}
ExitIfErrors()
// Phase 5: Inlining
timings.Start("fe", "inlining")
@ -674,14 +667,10 @@ func Main(archInit func(*Arch)) {
// otherwise lazily when used or re-exported.
for _, n := range importlist {
if n.Func.Inl != nil {
saveerrors()
typecheckinl(n)
}
}
if nsavederrors+nerrors != 0 {
errorexit()
}
ExitIfErrors()
}
if Debug.l != 0 {
@ -793,10 +782,7 @@ func Main(archInit func(*Arch)) {
// Check the map keys again, since we typechecked the external
// declarations.
checkMapKeys()
if nerrors+nsavederrors != 0 {
errorexit()
}
ExitIfErrors()
// Write object data to disk.
timings.Start("be", "dumpobj")
@ -827,10 +813,7 @@ func Main(archInit func(*Arch)) {
}
logopt.FlushLoggedOpts(Ctxt, myimportpath)
if nerrors+nsavederrors != 0 {
errorexit()
}
ExitIfErrors()
flusherrors()
timings.Stop()
@ -1011,11 +994,6 @@ func readSymABIs(file, myimportpath string) {
}
}
func saveerrors() {
nsavederrors += nerrors
nerrors = 0
}
func arsize(b *bufio.Reader, name string) int {
var buf [ArhdrSize]byte
if _, err := io.ReadFull(b, buf[:]); err != nil {
@ -1396,7 +1374,7 @@ func clearImports() {
// leave s->block set to cause redeclaration
// errors if a conflicting top-level name is
// introduced by a different file.
if !n.Name.Used() && nsyntaxerrors == 0 {
if !n.Name.Used() && SyntaxErrors() == 0 {
unused = append(unused, importedPkg{n.Pos, n.Name.Pkg.Path, s.Name})
}
s.Def = nil
@ -1405,7 +1383,7 @@ func clearImports() {
if IsAlias(s) {
// throw away top-level name left over
// from previous import . "x"
if n.Name != nil && n.Name.Pack != nil && !n.Name.Pack.Name.Used() && nsyntaxerrors == 0 {
if n.Name != nil && n.Name.Pack != nil && !n.Name.Pack.Name.Used() && SyntaxErrors() == 0 {
unused = append(unused, importedPkg{n.Name.Pack.Pos, n.Name.Pack.Name.Pkg.Path, ""})
n.Name.Pack.Name.SetUsed(true)
}

View File

@ -136,7 +136,7 @@ func (a *Mpflt) Float64() float64 {
x, _ := a.Val.Float64()
// check for overflow
if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
if math.IsInf(x, 0) && Errors() == 0 {
Fatalf("ovf in Mpflt Float64")
}
@ -148,7 +148,7 @@ func (a *Mpflt) Float32() float64 {
x := float64(x32)
// check for overflow
if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
if math.IsInf(x, 0) && Errors() == 0 {
Fatalf("ovf in Mpflt Float32")
}

View File

@ -72,7 +72,7 @@ func (a *Mpint) SetFloat(b *Mpflt) bool {
func (a *Mpint) Add(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
if Errors() == 0 {
Fatalf("ovf in Mpint Add")
}
a.SetOverflow()
@ -88,7 +88,7 @@ func (a *Mpint) Add(b *Mpint) {
func (a *Mpint) Sub(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
if Errors() == 0 {
Fatalf("ovf in Mpint Sub")
}
a.SetOverflow()
@ -104,7 +104,7 @@ func (a *Mpint) Sub(b *Mpint) {
func (a *Mpint) Mul(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
if Errors() == 0 {
Fatalf("ovf in Mpint Mul")
}
a.SetOverflow()
@ -120,7 +120,7 @@ func (a *Mpint) Mul(b *Mpint) {
func (a *Mpint) Quo(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
if Errors() == 0 {
Fatalf("ovf in Mpint Quo")
}
a.SetOverflow()
@ -137,7 +137,7 @@ func (a *Mpint) Quo(b *Mpint) {
func (a *Mpint) Rem(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
if Errors() == 0 {
Fatalf("ovf in Mpint Rem")
}
a.SetOverflow()
@ -154,7 +154,7 @@ func (a *Mpint) Rem(b *Mpint) {
func (a *Mpint) Or(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
if Errors() == 0 {
Fatalf("ovf in Mpint Or")
}
a.SetOverflow()
@ -166,7 +166,7 @@ func (a *Mpint) Or(b *Mpint) {
func (a *Mpint) And(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
if Errors() == 0 {
Fatalf("ovf in Mpint And")
}
a.SetOverflow()
@ -178,7 +178,7 @@ func (a *Mpint) And(b *Mpint) {
func (a *Mpint) AndNot(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
if Errors() == 0 {
Fatalf("ovf in Mpint AndNot")
}
a.SetOverflow()
@ -190,7 +190,7 @@ func (a *Mpint) AndNot(b *Mpint) {
func (a *Mpint) Xor(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
if Errors() == 0 {
Fatalf("ovf in Mpint Xor")
}
a.SetOverflow()
@ -202,7 +202,7 @@ func (a *Mpint) Xor(b *Mpint) {
func (a *Mpint) Lsh(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
if Errors() == 0 {
Fatalf("ovf in Mpint Lsh")
}
a.SetOverflow()
@ -229,7 +229,7 @@ func (a *Mpint) Lsh(b *Mpint) {
func (a *Mpint) Rsh(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
if Errors() == 0 {
Fatalf("ovf in Mpint Rsh")
}
a.SetOverflow()
@ -267,7 +267,7 @@ func (a *Mpint) Neg() {
func (a *Mpint) Int64() int64 {
if a.Ovf {
if nsavederrors+nerrors == 0 {
if Errors() == 0 {
Fatalf("constant overflow")
}
return 0

View File

@ -64,7 +64,7 @@ func parseFiles(filenames []string) uint {
lines += p.file.Lines
p.file = nil // release memory
if nsyntaxerrors != 0 {
if SyntaxErrors() != 0 {
errorexit()
}
// Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure.
@ -333,7 +333,7 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
val := p.basicLit(imp.Path)
ipkg := importfile(&val)
if ipkg == nil {
if nerrors == 0 {
if Errors() == 0 {
Fatalf("phase error in import")
}
return

View File

@ -198,7 +198,7 @@ func funccompile(fn *Node) {
}
if fn.Type == nil {
if nerrors == 0 {
if Errors() == 0 {
Fatalf("funccompile missing type")
}
return
@ -224,10 +224,9 @@ func funccompile(fn *Node) {
}
func compile(fn *Node) {
saveerrors()
errorsBefore := Errors()
order(fn)
if nerrors != 0 {
if Errors() > errorsBefore {
return
}
@ -237,7 +236,7 @@ func compile(fn *Node) {
fn.Func.initLSym(true)
walk(fn)
if nerrors != 0 {
if Errors() > errorsBefore {
return
}
if instrumenting {

View File

@ -0,0 +1,243 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gc
import (
"cmd/internal/objabi"
"cmd/internal/src"
"fmt"
"os"
"runtime/debug"
"sort"
"strings"
)
// An errorMsg is a queued error message, waiting to be printed.
type errorMsg struct {
pos src.XPos
msg string
}
// Pos is the current source position being processed,
// printed by Errorf, ErrorfLang, Fatalf, and Warnf.
var lineno src.XPos
var (
errorMsgs []errorMsg
numErrors int // number of entries in errorMsgs that are errors (as opposed to warnings)
numSyntaxErrors int
)
// Errors returns the number of errors reported.
func Errors() int {
return numErrors
}
// SyntaxErrors returns the number of syntax errors reported
func SyntaxErrors() int {
return numSyntaxErrors
}
// addErrorMsg adds a new errorMsg (which may be a warning) to errorMsgs.
func addErrorMsg(pos src.XPos, format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
// Only add the position if know the position.
// See issue golang.org/issue/11361.
if pos.IsKnown() {
msg = fmt.Sprintf("%v: %s", linestr(pos), msg)
}
errorMsgs = append(errorMsgs, errorMsg{
pos: pos,
msg: msg + "\n",
})
}
// FmtPos formats pos as a file:line string.
func linestr(pos src.XPos) string {
if Ctxt == nil {
return "???"
}
return Ctxt.OutermostPos(pos).Format(Debug.C == 0, Debug.L == 1)
}
// byPos sorts errors by source position.
type byPos []errorMsg
func (x byPos) Len() int { return len(x) }
func (x byPos) Less(i, j int) bool { return x[i].pos.Before(x[j].pos) }
func (x byPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
// FlushErrors sorts errors seen so far by line number, prints them to stdout,
// and empties the errors array.
func flusherrors() {
Ctxt.Bso.Flush()
if len(errorMsgs) == 0 {
return
}
sort.Stable(byPos(errorMsgs))
for i, err := range errorMsgs {
if i == 0 || err.msg != errorMsgs[i-1].msg {
fmt.Printf("%s", err.msg)
}
}
errorMsgs = errorMsgs[:0]
}
// lasterror keeps track of the most recently issued error,
// to avoid printing multiple error messages on the same line.
var lasterror struct {
syntax src.XPos // source position of last syntax error
other src.XPos // source position of last non-syntax error
msg string // error message of last non-syntax error
}
// sameline reports whether two positions a, b are on the same line.
func sameline(a, b src.XPos) bool {
p := Ctxt.PosTable.Pos(a)
q := Ctxt.PosTable.Pos(b)
return p.Base() == q.Base() && p.Line() == q.Line()
}
// Errorf reports a formatted error at the current line.
func yyerror(format string, args ...interface{}) {
yyerrorl(lineno, format, args...)
}
// ErrorfAt reports a formatted error message at pos.
func yyerrorl(pos src.XPos, format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
if strings.HasPrefix(msg, "syntax error") {
numSyntaxErrors++
// only one syntax error per line, no matter what error
if sameline(lasterror.syntax, pos) {
return
}
lasterror.syntax = pos
} else {
// only one of multiple equal non-syntax errors per line
// (flusherrors shows only one of them, so we filter them
// here as best as we can (they may not appear in order)
// so that we don't count them here and exit early, and
// then have nothing to show for.)
if sameline(lasterror.other, pos) && lasterror.msg == msg {
return
}
lasterror.other = pos
lasterror.msg = msg
}
addErrorMsg(pos, "%s", msg)
numErrors++
hcrash()
if numErrors >= 10 && Debug.e == 0 {
flusherrors()
fmt.Printf("%v: too many errors\n", linestr(pos))
errorexit()
}
}
// ErrorfVers reports that a language feature (format, args) requires a later version of Go.
func yyerrorv(lang string, format string, args ...interface{}) {
yyerror("%s requires %s or later (-lang was set to %s; check go.mod)", fmt.Sprintf(format, args...), lang, flag_lang)
}
// UpdateErrorDot is a clumsy hack that rewrites the last error,
// if it was "LINE: undefined: NAME", to be "LINE: undefined: NAME in EXPR".
// It is used to give better error messages for dot (selector) expressions.
func UpdateErrorDot(line string, name, expr string) {
if len(errorMsgs) == 0 {
return
}
e := &errorMsgs[len(errorMsgs)-1]
if strings.HasPrefix(e.msg, line) && e.msg == fmt.Sprintf("%v: undefined: %v\n", line, name) {
e.msg = fmt.Sprintf("%v: undefined: %v in %v\n", line, name, expr)
}
}
// Warnf reports a formatted warning at the current line.
// In general the Go compiler does NOT generate warnings,
// so this should be used only when the user has opted in
// to additional output by setting a particular flag.
func Warn(format string, args ...interface{}) {
Warnl(lineno, format, args...)
}
// WarnfAt reports a formatted warning at pos.
// In general the Go compiler does NOT generate warnings,
// so this should be used only when the user has opted in
// to additional output by setting a particular flag.
func Warnl(pos src.XPos, format string, args ...interface{}) {
addErrorMsg(pos, format, args...)
if Debug.m != 0 {
flusherrors()
}
}
// Fatal reports a fatal error - an internal problem - at the current line and exits.
// If other errors have already been printed, then Fatal just quietly exits.
// (The internal problem may have been caused by incomplete information
// after the already-reported errors, so best to let users fix those and
// try again without being bothered about a spurious internal error.)
//
// But if no errors have been printed, or if -d panic has been specified,
// Fatal prints the error as an "internal compiler error". In a released build,
// it prints an error asking to file a bug report. In development builds, it
// prints a stack trace.
//
// If -h has been specified, Fatal panics to force the usual runtime info dump.
func Fatalf(format string, args ...interface{}) {
flusherrors()
if Debug_panic != 0 || numErrors == 0 {
fmt.Printf("%v: internal compiler error: ", linestr(lineno))
fmt.Printf(format, args...)
fmt.Printf("\n")
// If this is a released compiler version, ask for a bug report.
if strings.HasPrefix(objabi.Version, "go") {
fmt.Printf("\n")
fmt.Printf("Please file a bug report including a short program that triggers the error.\n")
fmt.Printf("https://golang.org/issue/new\n")
} else {
// Not a release; dump a stack trace, too.
fmt.Println()
os.Stdout.Write(debug.Stack())
fmt.Println()
}
}
hcrash()
errorexit()
}
// hcrash crashes the compiler when -h is set, to find out where a message is generated.
func hcrash() {
if Debug.h != 0 {
flusherrors()
if outfile != "" {
os.Remove(outfile)
}
panic("-h")
}
}
// ErrorExit handles an error-status exit.
// It flushes any pending errors, removes the output file, and exits.
func errorexit() {
flusherrors()
if outfile != "" {
os.Remove(outfile)
}
os.Exit(2)
}
// ExitIfErrors calls ErrorExit if any errors have been reported.
func ExitIfErrors() {
if Errors() > 0 {
errorexit()
}
}

View File

@ -6,13 +6,10 @@ package gc
import (
"cmd/compile/internal/types"
"cmd/internal/objabi"
"cmd/internal/src"
"crypto/md5"
"encoding/binary"
"fmt"
"os"
"runtime/debug"
"sort"
"strconv"
"strings"
@ -21,13 +18,6 @@ import (
"unicode/utf8"
)
type Error struct {
pos src.XPos
msg string
}
var errors []Error
// largeStack is info about a function whose stack frame is too large (rare).
type largeStack struct {
locals int64
@ -41,170 +31,6 @@ var (
largeStackFrames []largeStack
)
func errorexit() {
flusherrors()
if outfile != "" {
os.Remove(outfile)
}
os.Exit(2)
}
func adderrorname(n *Node) {
if n.Op != ODOT {
return
}
old := fmt.Sprintf("%v: undefined: %v\n", n.Line(), n.Left)
if len(errors) > 0 && errors[len(errors)-1].pos.Line() == n.Pos.Line() && errors[len(errors)-1].msg == old {
errors[len(errors)-1].msg = fmt.Sprintf("%v: undefined: %v in %v\n", n.Line(), n.Left, n)
}
}
func adderr(pos src.XPos, format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
// Only add the position if know the position.
// See issue golang.org/issue/11361.
if pos.IsKnown() {
msg = fmt.Sprintf("%v: %s", linestr(pos), msg)
}
errors = append(errors, Error{
pos: pos,
msg: msg + "\n",
})
}
// byPos sorts errors by source position.
type byPos []Error
func (x byPos) Len() int { return len(x) }
func (x byPos) Less(i, j int) bool { return x[i].pos.Before(x[j].pos) }
func (x byPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
// flusherrors sorts errors seen so far by line number, prints them to stdout,
// and empties the errors array.
func flusherrors() {
Ctxt.Bso.Flush()
if len(errors) == 0 {
return
}
sort.Stable(byPos(errors))
for i, err := range errors {
if i == 0 || err.msg != errors[i-1].msg {
fmt.Printf("%s", err.msg)
}
}
errors = errors[:0]
}
func hcrash() {
if Debug.h != 0 {
flusherrors()
if outfile != "" {
os.Remove(outfile)
}
var x *int
*x = 0
}
}
func linestr(pos src.XPos) string {
return Ctxt.OutermostPos(pos).Format(Debug.C == 0, Debug.L == 1)
}
// lasterror keeps track of the most recently issued error.
// It is used to avoid multiple error messages on the same
// line.
var lasterror struct {
syntax src.XPos // source position of last syntax error
other src.XPos // source position of last non-syntax error
msg string // error message of last non-syntax error
}
// sameline reports whether two positions a, b are on the same line.
func sameline(a, b src.XPos) bool {
p := Ctxt.PosTable.Pos(a)
q := Ctxt.PosTable.Pos(b)
return p.Base() == q.Base() && p.Line() == q.Line()
}
func yyerrorl(pos src.XPos, format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
if strings.HasPrefix(msg, "syntax error") {
nsyntaxerrors++
// only one syntax error per line, no matter what error
if sameline(lasterror.syntax, pos) {
return
}
lasterror.syntax = pos
} else {
// only one of multiple equal non-syntax errors per line
// (flusherrors shows only one of them, so we filter them
// here as best as we can (they may not appear in order)
// so that we don't count them here and exit early, and
// then have nothing to show for.)
if sameline(lasterror.other, pos) && lasterror.msg == msg {
return
}
lasterror.other = pos
lasterror.msg = msg
}
adderr(pos, "%s", msg)
hcrash()
nerrors++
if nsavederrors+nerrors >= 10 && Debug.e == 0 {
flusherrors()
fmt.Printf("%v: too many errors\n", linestr(pos))
errorexit()
}
}
func yyerrorv(lang string, format string, args ...interface{}) {
what := fmt.Sprintf(format, args...)
yyerrorl(lineno, "%s requires %s or later (-lang was set to %s; check go.mod)", what, lang, flag_lang)
}
func yyerror(format string, args ...interface{}) {
yyerrorl(lineno, format, args...)
}
func Warn(fmt_ string, args ...interface{}) {
Warnl(lineno, fmt_, args...)
}
func Warnl(line src.XPos, fmt_ string, args ...interface{}) {
adderr(line, fmt_, args...)
if Debug.m != 0 {
flusherrors()
}
}
func Fatalf(fmt_ string, args ...interface{}) {
flusherrors()
if Debug_panic != 0 || nsavederrors+nerrors == 0 {
fmt.Printf("%v: internal compiler error: ", linestr(lineno))
fmt.Printf(fmt_, args...)
fmt.Printf("\n")
// If this is a released compiler version, ask for a bug report.
if strings.HasPrefix(objabi.Version, "go") {
fmt.Printf("\n")
fmt.Printf("Please file a bug report including a short program that triggers the error.\n")
fmt.Printf("https://golang.org/issue/new\n")
} else {
// Not a release; dump a stack trace, too.
fmt.Println()
os.Stdout.Write(debug.Stack())
fmt.Println()
}
}
hcrash()
errorexit()
}
// hasUniquePos reports whether n has a unique position that can be
// used for reporting error messages.
//

View File

@ -280,7 +280,7 @@ func typecheck(n *Node, top int) (res *Node) {
yyerrorl(n.Pos, "constant definition loop%s", cycleTrace(cycleFor(n)))
}
if nsavederrors+nerrors == 0 {
if Errors() == 0 {
var trace string
for i := len(typecheck_tcstack) - 1; i >= 0; i-- {
x := typecheck_tcstack[i]
@ -891,7 +891,7 @@ func typecheck1(n *Node, top int) (res *Node) {
t := n.Left.Type
if t == nil {
adderrorname(n)
UpdateErrorDot(n.Line(), n.Left.String(), n.String())
n.Type = nil
return n
}
@ -3641,7 +3641,7 @@ func typecheckdef(n *Node) {
if n.SubOp() != 0 { // like OPRINTN
break
}
if nsavederrors+nerrors > 0 {
if Errors() > 0 {
// Can have undefined variables in x := foo
// that make x have an n.name.Defn == nil.
// If there are other errors anyway, don't
@ -3686,9 +3686,9 @@ func typecheckdef(n *Node) {
n.SetWalkdef(1)
setTypeNode(n, types.New(TFORW))
n.Type.Sym = n.Sym
nerrors0 := nerrors
errorsBefore := Errors()
typecheckdeftype(n)
if n.Type.Etype == TFORW && nerrors > nerrors0 {
if n.Type.Etype == TFORW && Errors() > errorsBefore {
// Something went wrong during type-checking,
// but it was reported. Silence future errors.
n.Type.SetBroke(true)

View File

@ -20,6 +20,7 @@ const zeroValSize = 1024 // must match value of runtime/map.go:maxZero
func walk(fn *Node) {
Curfn = fn
errorsBefore := Errors()
if Debug.W != 0 {
s := fmt.Sprintf("\nbefore walk %v", Curfn.Func.Nname.Sym)
@ -59,7 +60,7 @@ func walk(fn *Node) {
}
lineno = lno
if nerrors != 0 {
if Errors() > errorsBefore {
return
}
walkstmtlist(Curfn.Nbody.Slice())