mirror of
https://github.com/golang/go
synced 2024-11-07 15:26:11 -07:00
go/types: record type information after detecting error
The existing implementation stops recording type information once it encounters an error. This results in missing type information that is needed by various tools. This change handles a few commonly encountered cases by continuing to check subtrees after errors. Also, add tests for cases where the package fails to type-check. Updates #22467 Change-Id: I1bb48d4cb8ae5548dca63bdd785ea2f69329e92b Reviewed-on: https://go-review.googlesource.com/123578 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
71d2908648
commit
6f8e8e14c8
@ -26,7 +26,6 @@ func pkgFor(path, source string, info *Info) (*Package, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conf := Config{Importer: importer.Default()}
|
||||
return conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
|
||||
}
|
||||
@ -43,6 +42,20 @@ func mustTypecheck(t *testing.T, path, source string, info *Info) string {
|
||||
return pkg.Name()
|
||||
}
|
||||
|
||||
func maybeTypecheck(t *testing.T, path, source string, info *Info) string {
|
||||
fset := token.NewFileSet()
|
||||
f, err := parser.ParseFile(fset, path, source, 0)
|
||||
if f == nil { // ignore errors unless f is nil
|
||||
t.Fatalf("%s: unable to parse: %s", path, err)
|
||||
}
|
||||
conf := Config{
|
||||
Error: func(err error) {},
|
||||
Importer: importer.Default(),
|
||||
}
|
||||
pkg, _ := conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
|
||||
return pkg.Name()
|
||||
}
|
||||
|
||||
func TestValuesInfo(t *testing.T) {
|
||||
var tests = []struct {
|
||||
src string
|
||||
@ -243,11 +256,16 @@ func TestTypesInfo(t *testing.T) {
|
||||
`<-ch`,
|
||||
`(string, bool)`,
|
||||
},
|
||||
|
||||
// tests for broken code that doesn't parse or type-check
|
||||
{`package x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
|
||||
{`package x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
|
||||
{`package x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a; f: b;}}`, `b`, `string`},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
info := Info{Types: make(map[ast.Expr]TypeAndValue)}
|
||||
name := mustTypecheck(t, "TypesInfo", test.src, &info)
|
||||
name := maybeTypecheck(t, "TypesInfo", test.src, &info)
|
||||
|
||||
// look for expression type
|
||||
var typ Type
|
||||
|
@ -310,6 +310,7 @@ func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) {
|
||||
check.recordDef(ident, obj)
|
||||
}
|
||||
} else {
|
||||
check.expr(&operand{}, lhs)
|
||||
check.errorf(lhs.Pos(), "cannot declare %s", lhs)
|
||||
}
|
||||
if obj == nil {
|
||||
|
@ -34,6 +34,9 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
|
||||
check.conversion(x, T)
|
||||
}
|
||||
default:
|
||||
for _, arg := range e.Args {
|
||||
check.expr(&operand{}, arg)
|
||||
}
|
||||
check.errorf(e.Args[n-1].Pos(), "too many arguments in conversion to %s", T)
|
||||
}
|
||||
x.expr = e
|
||||
|
@ -1094,6 +1094,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||
continue
|
||||
}
|
||||
key, _ := kv.Key.(*ast.Ident)
|
||||
check.expr(x, kv.Value)
|
||||
if key == nil {
|
||||
check.errorf(kv.Pos(), "invalid field name %s in struct literal", kv.Key)
|
||||
continue
|
||||
@ -1105,15 +1106,14 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||
}
|
||||
fld := fields[i]
|
||||
check.recordUse(key, fld)
|
||||
etyp := fld.typ
|
||||
check.assignment(x, etyp, "struct literal")
|
||||
// 0 <= i < len(fields)
|
||||
if visited[i] {
|
||||
check.errorf(kv.Pos(), "duplicate field name %s in struct literal", key.Name)
|
||||
continue
|
||||
}
|
||||
visited[i] = true
|
||||
check.expr(x, kv.Value)
|
||||
etyp := fld.typ
|
||||
check.assignment(x, etyp, "struct literal")
|
||||
}
|
||||
} else {
|
||||
// no element must have a key
|
||||
|
Loading…
Reference in New Issue
Block a user