cmd/vet: avoid internal error for implicitly declared type switch vars
For type switches using a short variable declaration of the form
switch t := x.(type) {
case T1:
...
go/types doesn't declare the symbolic variable (t in this example)
with the switch; thus such variables are not found in types.Info.Defs.
Instead they are implicitly declared with each type switch case,
and can be found in types.Info.Implicits.
Adjust the shadowing code accordingly.
Added a test case to verify that the issue is fixed, and a test
case verifying that the shadowing code now considers implicitly
declared variables introduces in type switch cases.
While at it, also fixed the (internal) error reporting to provide
more accurate information.
Fixe #26725.
Change-Id: If408ed9e692bf47c640f81de8f46bf5eb43415b0
Reviewed-on: https://go-review.googlesource.com/135117
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Daniel Martà <mvdan@mvdan.cc>
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go
index c50d488..646adf4 100644
--- a/src/cmd/vet/main.go
+++ b/src/cmd/vet/main.go
@@ -467,6 +467,7 @@
path string
defs map[*ast.Ident]types.Object
uses map[*ast.Ident]types.Object
+ implicits map[ast.Node]types.Object
selectors map[*ast.SelectorExpr]*types.Selection
types map[ast.Expr]types.TypeAndValue
spans map[types.Object]Span
diff --git a/src/cmd/vet/shadow.go b/src/cmd/vet/shadow.go
index 29c952f..47a4883 100644
--- a/src/cmd/vet/shadow.go
+++ b/src/cmd/vet/shadow.go
@@ -86,14 +86,11 @@
return s.min <= pos && pos < s.max
}
-// growSpan expands the span for the object to contain the instance represented
-// by the identifier.
-func (pkg *Package) growSpan(ident *ast.Ident, obj types.Object) {
+// growSpan expands the span for the object to contain the source range [pos, end).
+func (pkg *Package) growSpan(obj types.Object, pos, end token.Pos) {
if *strictShadowing {
return // No need
}
- pos := ident.Pos()
- end := ident.End()
span, ok := pkg.spans[obj]
if ok {
if span.min > pos {
@@ -232,7 +229,7 @@
// the shadowing identifier.
span, ok := f.pkg.spans[shadowed]
if !ok {
- f.Badf(ident.Pos(), "internal error: no range for %q", ident.Name)
+ f.Badf(shadowed.Pos(), "internal error: no range for %q", shadowed.Name())
return
}
if !span.contains(ident.Pos()) {
diff --git a/src/cmd/vet/testdata/shadow.go b/src/cmd/vet/testdata/shadow.go
index c55cb27..d10fde2 100644
--- a/src/cmd/vet/testdata/shadow.go
+++ b/src/cmd/vet/testdata/shadow.go
@@ -57,3 +57,35 @@
func one() int {
return 1
}
+
+// Must not complain with an internal error for the
+// implicitly declared type switch variable v.
+func issue26725(x interface{}) int {
+ switch v := x.(type) {
+ case int, int32:
+ if v, ok := x.(int); ok {
+ return v
+ }
+ case int64:
+ return int(v)
+ }
+ return 0
+}
+
+// Verify that implicitly declared variables from
+// type switches are considered in shadowing analysis.
+func shadowTypeSwitch(a interface{}) {
+ switch t := a.(type) {
+ case int:
+ {
+ t := 0 // ERROR "declaration of .t. shadows declaration at shadow.go:78"
+ _ = t
+ }
+ _ = t
+ case uint:
+ {
+ t := uint(0) // OK because t is not mentioned later in this function
+ _ = t
+ }
+ }
+}
diff --git a/src/cmd/vet/types.go b/src/cmd/vet/types.go
index 5f8e481..3ff4b59 100644
--- a/src/cmd/vet/types.go
+++ b/src/cmd/vet/types.go
@@ -73,6 +73,7 @@
}
pkg.defs = make(map[*ast.Ident]types.Object)
pkg.uses = make(map[*ast.Ident]types.Object)
+ pkg.implicits = make(map[ast.Node]types.Object)
pkg.selectors = make(map[*ast.SelectorExpr]*types.Selection)
pkg.spans = make(map[types.Object]Span)
pkg.types = make(map[ast.Expr]types.TypeAndValue)
@@ -95,6 +96,7 @@
Types: pkg.types,
Defs: pkg.defs,
Uses: pkg.uses,
+ Implicits: pkg.implicits,
}
typesPkg, err := config.Check(pkg.path, fs, astFiles, info)
if len(allErrors) == 0 && err != nil {
@@ -103,10 +105,28 @@
pkg.typesPkg = typesPkg
// update spans
for id, obj := range pkg.defs {
- pkg.growSpan(id, obj)
+ // Ignore identifiers that don't denote objects
+ // (package names, symbolic variables such as t
+ // in t := x.(type) of type switch headers).
+ if obj != nil {
+ pkg.growSpan(obj, id.Pos(), id.End())
+ }
}
for id, obj := range pkg.uses {
- pkg.growSpan(id, obj)
+ pkg.growSpan(obj, id.Pos(), id.End())
+ }
+ for node, obj := range pkg.implicits {
+ // A type switch with a short variable declaration
+ // such as t := x.(type) doesn't declare the symbolic
+ // variable (t in the example) at the switch header;
+ // instead a new variable t (with specific type) is
+ // declared implicitly for each case. Such variables
+ // are found in the types.Info.Implicits (not Defs)
+ // map. Add them here, assuming they are declared at
+ // the type cases' colon ":".
+ if cc, ok := node.(*ast.CaseClause); ok {
+ pkg.growSpan(obj, cc.Colon, cc.Colon)
+ }
}
return allErrors
}