diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index 1d3c32520a..700fde9231 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -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 diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go index cb0fe3bc3a..6adef3b407 100644 --- a/src/go/types/assignments.go +++ b/src/go/types/assignments.go @@ -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 { diff --git a/src/go/types/call.go b/src/go/types/call.go index 1b40651b73..4e8544ad88 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -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 diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 39ee6bcca3..60ac4a33ad 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -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