mirror of
https://github.com/golang/go.git
synced 2025-05-21 07:13:27 +00:00
go/types: avoid repeated "declared but not used" errors for closure variables
At the end of type-checking a function or closure, unused local variables are reported by looking at all variables in the function scope and its nested children scopes. If a nested scope belonged to a nested function (closure), that scope would be searched twice, leading to multiple error messages for unused variables. This CL introduces an internal-only marker to identify function scopes so that they can be ignored where needed. Fixes #22524. Change-Id: If58cc17b2f0615a16f33ea262f50dffd0e86d0f0 Reviewed-on: https://go-review.googlesource.com/75251 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
eb2b0ed5b5
commit
a0dfd82f41
@ -1030,6 +1030,15 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||
// Anonymous functions are considered part of the
|
||||
// init expression/func declaration which contains
|
||||
// them: use existing package-level declaration info.
|
||||
//
|
||||
// TODO(gri) We delay type-checking of regular (top-level)
|
||||
// function bodies until later. Why don't we do
|
||||
// it for closures of top-level expressions?
|
||||
// (We can't easily do it for local closures
|
||||
// because the surrounding scopes must reflect
|
||||
// the exact position where the closure appears
|
||||
// in the source; e.g., variables declared below
|
||||
// must not be visible).
|
||||
check.funcBody(check.decl, "", sig, e.Body)
|
||||
x.mode = value
|
||||
x.typ = sig
|
||||
|
@ -28,12 +28,13 @@ type Scope struct {
|
||||
elems map[string]Object // lazily allocated
|
||||
pos, end token.Pos // scope extent; may be invalid
|
||||
comment string // for debugging only
|
||||
isFunc bool // set if this is a function scope (internal use only)
|
||||
}
|
||||
|
||||
// NewScope returns a new, empty scope contained in the given parent
|
||||
// scope, if any. The comment is for debugging only.
|
||||
func NewScope(parent *Scope, pos, end token.Pos, comment string) *Scope {
|
||||
s := &Scope{parent, nil, nil, pos, end, comment}
|
||||
s := &Scope{parent, nil, nil, pos, end, comment, false}
|
||||
// don't add children to Universe scope!
|
||||
if parent != nil && parent != Universe {
|
||||
parent.children = append(parent.children, s)
|
||||
|
@ -72,7 +72,11 @@ func (check *Checker) usage(scope *Scope) {
|
||||
}
|
||||
|
||||
for _, scope := range scope.children {
|
||||
check.usage(scope)
|
||||
// Don't go inside closure scopes a second time;
|
||||
// they are handled explicitly by funcBody.
|
||||
if !scope.isFunc {
|
||||
check.usage(scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
7
src/go/types/testdata/vardecl.src
vendored
7
src/go/types/testdata/vardecl.src
vendored
@ -151,6 +151,13 @@ func (r T) _(a, b, c int) (u, v, w int) {
|
||||
return
|
||||
}
|
||||
|
||||
// Unused variables in closures must lead to only one error (issue #22524).
|
||||
func _() {
|
||||
_ = func() {
|
||||
var x /* ERROR declared but not used */ int
|
||||
}
|
||||
}
|
||||
|
||||
// Invalid (unused) expressions must not lead to spurious "declared but not used errors"
|
||||
func _() {
|
||||
var a, b, c int
|
||||
|
@ -143,6 +143,7 @@ func (check *Checker) typ(e ast.Expr) Type {
|
||||
// funcType type-checks a function or method type.
|
||||
func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) {
|
||||
scope := NewScope(check.scope, token.NoPos, token.NoPos, "function")
|
||||
scope.isFunc = true
|
||||
check.recordScope(ftyp, scope)
|
||||
|
||||
recvList, _ := check.collectParams(scope, recvPar, false)
|
||||
|
Loading…
x
Reference in New Issue
Block a user