]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: better errors for non-existing fields or methods
authorRobert Griesemer <gri@golang.org>
Wed, 31 Jan 2024 23:02:31 +0000 (15:02 -0800)
committerRobert Griesemer <gri@google.com>
Wed, 7 Feb 2024 16:41:56 +0000 (16:41 +0000)
This CL improves the error messages reported when a field or method
name is used that doesn't exist. It brings the error messges on par
(or better) with the respective errors reported before Go 1.18 (i.e.
before switching to the new type checker):

Make case distinctions based on whether a field/method is exported
and how it is spelled. Factor out that logic into a new function
(lookupError) in a new file (errsupport.go), which is generated for
go/types. Use lookupError when reporting selector lookup errors
and missing struct field keys.

Add a comprehensive set of tests (lookup2.go) and spot tests for
the two cases brought up by the issue at hand.

Adjusted existing tests as needed.

Fixes #49736.

Change-Id: I2f439948dcd12f9bd1a258367862d8ff96e32305
Reviewed-on: https://go-review.googlesource.com/c/go/+/560055
Run-TryBot: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
12 files changed:
src/cmd/compile/internal/types2/call.go
src/cmd/compile/internal/types2/errsupport.go [new file with mode: 0644]
src/cmd/compile/internal/types2/expr.go
src/go/types/call.go
src/go/types/errsupport.go [new file with mode: 0644]
src/go/types/expr.go
src/go/types/generate_test.go
src/internal/types/testdata/check/lookup1.go [moved from src/internal/types/testdata/check/lookup.go with 94% similarity]
src/internal/types/testdata/check/lookup2.go [new file with mode: 0644]
src/internal/types/testdata/fixedbugs/issue49736.go [new file with mode: 0644]
test/fixedbugs/issue22794.go
test/fixedbugs/issue25727.go

index 0ad58e07722cf6d4b9f147f922400f511dd0a4b3..b8f8a418bb8648b064c145020b413820c5e66e88 100644 (file)
@@ -824,22 +824,8 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *TypeName
                if isInterfacePtr(x.typ) {
                        why = check.interfacePtrError(x.typ)
                } else {
-                       why = check.sprintf("type %s has no field or method %s", x.typ, sel)
-                       // check if there's a field or method with different capitalization
-                       if obj, _, _ = lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel, true); obj != nil {
-                               var what string // empty or description with trailing space " " (default case, should never be reached)
-                               switch obj.(type) {
-                               case *Var:
-                                       what = "field "
-                               case *Func:
-                                       what = "method "
-                               }
-                               if samePkg(obj.Pkg(), check.pkg) || obj.Exported() {
-                                       why = check.sprintf("%s, but does have %s%s", why, what, obj.Name())
-                               } else if obj.Name() == sel {
-                                       why = check.sprintf("%s%s is not exported", what, obj.Name())
-                               }
-                       }
+                       alt, _, _ := lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel, true)
+                       why = check.lookupError(x.typ, sel, alt, false)
                }
                check.errorf(e.Sel, MissingFieldOrMethod, "%s.%s undefined (%s)", x.expr, sel, why)
                goto Error
diff --git a/src/cmd/compile/internal/types2/errsupport.go b/src/cmd/compile/internal/types2/errsupport.go
new file mode 100644 (file)
index 0000000..168150f
--- /dev/null
@@ -0,0 +1,113 @@
+// Copyright 2024 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.
+
+// This file implements support functions for error messages.
+
+package types2
+
+// lookupError returns a case-specific error when a lookup of selector sel in the
+// given type fails but an object with alternative spelling (case folding) is found.
+// If structLit is set, the error message is specifically for struct literal fields.
+func (check *Checker) lookupError(typ Type, sel string, obj Object, structLit bool) string {
+       // Provide more detail if there is an unexported object, or one with different capitalization.
+       // If selector and object are in the same package (==), export doesn't matter, otherwise (!=) it does.
+       // Messages depend on whether it's a general lookup or a field lookup in a struct literal.
+       //
+       // case           sel     pkg   have   message (examples for general lookup)
+       // ---------------------------------------------------------------------------------------------------------
+       // ok             x.Foo   ==    Foo
+       // misspelled     x.Foo   ==    FoO    type X has no field or method Foo, but does have field FoO
+       // misspelled     x.Foo   ==    foo    type X has no field or method Foo, but does have field foo
+       // misspelled     x.Foo   ==    foO    type X has no field or method Foo, but does have field foO
+       //
+       // misspelled     x.foo   ==    Foo    type X has no field or method foo, but does have field Foo
+       // misspelled     x.foo   ==    FoO    type X has no field or method foo, but does have field FoO
+       // ok             x.foo   ==    foo
+       // misspelled     x.foo   ==    foO    type X has no field or method foo, but does have field foO
+       //
+       // ok             x.Foo   !=    Foo
+       // misspelled     x.Foo   !=    FoO    type X has no field or method Foo, but does have field FoO
+       // unexported     x.Foo   !=    foo    type X has no field or method Foo, but does have unexported field foo
+       // missing        x.Foo   !=    foO    type X has no field or method Foo
+       //
+       // misspelled     x.foo   !=    Foo    type X has no field or method foo, but does have field Foo
+       // missing        x.foo   !=    FoO    type X has no field or method foo
+       // inaccessible   x.foo   !=    foo    cannot refer to unexported field foo
+       // missing        x.foo   !=    foO    type X has no field or method foo
+
+       const (
+               ok           = iota
+               missing      // no object found
+               misspelled   // found object with different spelling
+               unexported   // found object with name differing only in first letter
+               inaccessible // found object with matching name but inaccessible from the current package
+       )
+
+       // determine case
+       e := missing
+       var alt string // alternative spelling of selector; if any
+       if obj != nil {
+               alt = obj.Name()
+               if obj.Pkg() == check.pkg {
+                       assert(alt != sel) // otherwise there is no lookup error
+                       e = misspelled
+               } else if isExported(sel) {
+                       if isExported(alt) {
+                               e = misspelled
+                       } else if tail(sel) == tail(alt) {
+                               e = unexported
+                       }
+               } else if isExported(alt) {
+                       if tail(sel) == tail(alt) {
+                               e = misspelled
+                       }
+               } else if sel == alt {
+                       e = inaccessible
+               }
+       }
+
+       if structLit {
+               switch e {
+               case missing:
+                       return check.sprintf("unknown field %s in struct literal of type %s", sel, typ)
+               case misspelled:
+                       return check.sprintf("unknown field %s in struct literal of type %s, but does have %s", sel, typ, alt)
+               case unexported:
+                       return check.sprintf("unknown field %s in struct literal of type %s, but does have unexported %s", sel, typ, alt)
+               case inaccessible:
+                       return check.sprintf("cannot refer to unexported field %s in struct literal of type %s", alt, typ)
+               }
+       } else {
+               what := "object"
+               switch obj.(type) {
+               case *Var:
+                       what = "field"
+               case *Func:
+                       what = "method"
+               }
+               switch e {
+               case missing:
+                       return check.sprintf("type %s has no field or method %s", typ, sel)
+               case misspelled:
+                       return check.sprintf("type %s has no field or method %s, but does have %s %s", typ, sel, what, alt)
+               case unexported:
+                       return check.sprintf("type %s has no field or method %s, but does have unexported %s %s", typ, sel, what, alt)
+               case inaccessible:
+                       return check.sprintf("cannot refer to unexported %s %s", what, alt)
+               }
+       }
+
+       panic("unreachable")
+}
+
+// tail returns the string s without its first (UTF-8) character.
+// If len(s) == 0, the result is s.
+func tail(s string) string {
+       for i, _ := range s {
+               if i > 0 {
+                       return s[i:]
+               }
+       }
+       return s
+}
index 9504207f242a5090d26593145b2298b296491e6a..d7d60cc73cb6227e85228bc8caf9aeefb0334027 100644 (file)
@@ -1184,9 +1184,14 @@ func (check *Checker) exprInternal(T *target, x *operand, e syntax.Expr, hint Ty
                                                check.errorf(kv, InvalidLitField, "invalid field name %s in struct literal", kv.Key)
                                                continue
                                        }
-                                       i := fieldIndex(utyp.fields, check.pkg, key.Value, false)
+                                       i := fieldIndex(fields, check.pkg, key.Value, false)
                                        if i < 0 {
-                                               check.errorf(kv.Key, MissingLitField, "unknown field %s in struct literal of type %s", key.Value, base)
+                                               var alt Object
+                                               if j := fieldIndex(fields, check.pkg, key.Value, true); j >= 0 {
+                                                       alt = fields[j]
+                                               }
+                                               msg := check.lookupError(base, key.Value, alt, true)
+                                               check.error(kv.Key, MissingLitField, msg)
                                                continue
                                        }
                                        fld := fields[i]
index 5435e45f2582ae25d0a9dcbea15d19ec0dcbc6b1..cb90a2473617f85eb18774b226cbe419965b9dad 100644 (file)
@@ -826,22 +826,8 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *TypeName, w
                if isInterfacePtr(x.typ) {
                        why = check.interfacePtrError(x.typ)
                } else {
-                       why = check.sprintf("type %s has no field or method %s", x.typ, sel)
-                       // check if there's a field or method with different capitalization
-                       if obj, _, _ = lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel, true); obj != nil {
-                               var what string // empty or description with trailing space " " (default case, should never be reached)
-                               switch obj.(type) {
-                               case *Var:
-                                       what = "field "
-                               case *Func:
-                                       what = "method "
-                               }
-                               if samePkg(obj.Pkg(), check.pkg) || obj.Exported() {
-                                       why = check.sprintf("%s, but does have %s%s", why, what, obj.Name())
-                               } else if obj.Name() == sel {
-                                       why = check.sprintf("%s%s is not exported", what, obj.Name())
-                               }
-                       }
+                       alt, _, _ := lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel, true)
+                       why = check.lookupError(x.typ, sel, alt, false)
                }
                check.errorf(e.Sel, MissingFieldOrMethod, "%s.%s undefined (%s)", x.expr, sel, why)
                goto Error
diff --git a/src/go/types/errsupport.go b/src/go/types/errsupport.go
new file mode 100644 (file)
index 0000000..9519375
--- /dev/null
@@ -0,0 +1,115 @@
+// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
+
+// Copyright 2024 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.
+
+// This file implements support functions for error messages.
+
+package types
+
+// lookupError returns a case-specific error when a lookup of selector sel in the
+// given type fails but an object with alternative spelling (case folding) is found.
+// If structLit is set, the error message is specifically for struct literal fields.
+func (check *Checker) lookupError(typ Type, sel string, obj Object, structLit bool) string {
+       // Provide more detail if there is an unexported object, or one with different capitalization.
+       // If selector and object are in the same package (==), export doesn't matter, otherwise (!=) it does.
+       // Messages depend on whether it's a general lookup or a field lookup in a struct literal.
+       //
+       // case           sel     pkg   have   message (examples for general lookup)
+       // ---------------------------------------------------------------------------------------------------------
+       // ok             x.Foo   ==    Foo
+       // misspelled     x.Foo   ==    FoO    type X has no field or method Foo, but does have field FoO
+       // misspelled     x.Foo   ==    foo    type X has no field or method Foo, but does have field foo
+       // misspelled     x.Foo   ==    foO    type X has no field or method Foo, but does have field foO
+       //
+       // misspelled     x.foo   ==    Foo    type X has no field or method foo, but does have field Foo
+       // misspelled     x.foo   ==    FoO    type X has no field or method foo, but does have field FoO
+       // ok             x.foo   ==    foo
+       // misspelled     x.foo   ==    foO    type X has no field or method foo, but does have field foO
+       //
+       // ok             x.Foo   !=    Foo
+       // misspelled     x.Foo   !=    FoO    type X has no field or method Foo, but does have field FoO
+       // unexported     x.Foo   !=    foo    type X has no field or method Foo, but does have unexported field foo
+       // missing        x.Foo   !=    foO    type X has no field or method Foo
+       //
+       // misspelled     x.foo   !=    Foo    type X has no field or method foo, but does have field Foo
+       // missing        x.foo   !=    FoO    type X has no field or method foo
+       // inaccessible   x.foo   !=    foo    cannot refer to unexported field foo
+       // missing        x.foo   !=    foO    type X has no field or method foo
+
+       const (
+               ok           = iota
+               missing      // no object found
+               misspelled   // found object with different spelling
+               unexported   // found object with name differing only in first letter
+               inaccessible // found object with matching name but inaccessible from the current package
+       )
+
+       // determine case
+       e := missing
+       var alt string // alternative spelling of selector; if any
+       if obj != nil {
+               alt = obj.Name()
+               if obj.Pkg() == check.pkg {
+                       assert(alt != sel) // otherwise there is no lookup error
+                       e = misspelled
+               } else if isExported(sel) {
+                       if isExported(alt) {
+                               e = misspelled
+                       } else if tail(sel) == tail(alt) {
+                               e = unexported
+                       }
+               } else if isExported(alt) {
+                       if tail(sel) == tail(alt) {
+                               e = misspelled
+                       }
+               } else if sel == alt {
+                       e = inaccessible
+               }
+       }
+
+       if structLit {
+               switch e {
+               case missing:
+                       return check.sprintf("unknown field %s in struct literal of type %s", sel, typ)
+               case misspelled:
+                       return check.sprintf("unknown field %s in struct literal of type %s, but does have %s", sel, typ, alt)
+               case unexported:
+                       return check.sprintf("unknown field %s in struct literal of type %s, but does have unexported %s", sel, typ, alt)
+               case inaccessible:
+                       return check.sprintf("cannot refer to unexported field %s in struct literal of type %s", alt, typ)
+               }
+       } else {
+               what := "object"
+               switch obj.(type) {
+               case *Var:
+                       what = "field"
+               case *Func:
+                       what = "method"
+               }
+               switch e {
+               case missing:
+                       return check.sprintf("type %s has no field or method %s", typ, sel)
+               case misspelled:
+                       return check.sprintf("type %s has no field or method %s, but does have %s %s", typ, sel, what, alt)
+               case unexported:
+                       return check.sprintf("type %s has no field or method %s, but does have unexported %s %s", typ, sel, what, alt)
+               case inaccessible:
+                       return check.sprintf("cannot refer to unexported %s %s", what, alt)
+               }
+       }
+
+       panic("unreachable")
+}
+
+// tail returns the string s without its first (UTF-8) character.
+// If len(s) == 0, the result is s.
+func tail(s string) string {
+       for i, _ := range s {
+               if i > 0 {
+                       return s[i:]
+               }
+       }
+       return s
+}
index 5b5efd279f1d82c6ddcb48435b8e96d19745db52..95b460c848b6bde2f7019203835206b0561ec403 100644 (file)
@@ -1166,7 +1166,12 @@ func (check *Checker) exprInternal(T *target, x *operand, e ast.Expr, hint Type)
                                        }
                                        i := fieldIndex(utyp.fields, check.pkg, key.Name, false)
                                        if i < 0 {
-                                               check.errorf(kv, MissingLitField, "unknown field %s in struct literal of type %s", key.Name, base)
+                                               var alt Object
+                                               if j := fieldIndex(fields, check.pkg, key.Name, true); j >= 0 {
+                                                       alt = fields[j]
+                                               }
+                                               msg := check.lookupError(base, key.Name, alt, true)
+                                               check.error(kv.Key, MissingLitField, msg)
                                                continue
                                        }
                                        fld := fields[i]
index 59c0a97965c98428ac2d674f816e3c1e3f01444d..2208f56b7db2a1feb97639c8e78a47e307a27663 100644 (file)
@@ -103,6 +103,7 @@ var filemap = map[string]action{
        "const.go":          func(f *ast.File) { fixTokenPos(f) },
        "context.go":        nil,
        "context_test.go":   nil,
+       "errsupport.go":     nil,
        "gccgosizes.go":     nil,
        "gcsizes.go":        func(f *ast.File) { renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64") },
        "hilbert_test.go":   func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"`, `"go/types"`) },
similarity index 94%
rename from src/internal/types/testdata/check/lookup.go
rename to src/internal/types/testdata/check/lookup1.go
index 0b15d4515734f19f104cf30e88aec04352afe7f5..048288db773f6400d24cefe56aa2f0a4dd4e8e45 100644 (file)
@@ -62,12 +62,12 @@ func _() {
 func _() {
        var x big.Float
        _ = x.neg // ERROR "x.neg undefined (type big.Float has no field or method neg, but does have method Neg)"
-       _ = x.nEg // ERROR "x.nEg undefined (type big.Float has no field or method nEg, but does have method Neg)"
+       _ = x.nEg // ERROR "x.nEg undefined (type big.Float has no field or method nEg)"
        _ = x.Neg
        _ = x.NEg // ERROR "x.NEg undefined (type big.Float has no field or method NEg, but does have method Neg)"
 
-       _ = x.form // ERROR "x.form undefined (field form is not exported)"
+       _ = x.form // ERROR "x.form undefined (cannot refer to unexported field form)"
        _ = x.fOrm // ERROR "x.fOrm undefined (type big.Float has no field or method fOrm)"
-       _ = x.Form // ERROR "x.Form undefined (type big.Float has no field or method Form)"
+       _ = x.Form // ERROR "x.Form undefined (type big.Float has no field or method Form, but does have unexported field form)"
        _ = x.FOrm // ERROR "x.FOrm undefined (type big.Float has no field or method FOrm)"
 }
diff --git a/src/internal/types/testdata/check/lookup2.go b/src/internal/types/testdata/check/lookup2.go
new file mode 100644 (file)
index 0000000..a274da1
--- /dev/null
@@ -0,0 +1,94 @@
+// Copyright 2024 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 p
+
+import (
+       "go/ast"
+       "math/big"
+)
+
+// case           sel     pkg   have   message (examples for general lookup)
+// ---------------------------------------------------------------------------------------------------------
+// ok             x.Foo   ==    Foo
+// misspelled     x.Foo   ==    FoO    type X has no field or method Foo, but does have field FoO
+// misspelled     x.Foo   ==    foo    type X has no field or method Foo, but does have field foo
+// misspelled     x.Foo   ==    foO    type X has no field or method Foo, but does have field foO
+//
+// misspelled     x.foo   ==    Foo    type X has no field or method foo, but does have field Foo
+// misspelled     x.foo   ==    FoO    type X has no field or method foo, but does have field FoO
+// ok             x.foo   ==    foo
+// misspelled     x.foo   ==    foO    type X has no field or method foo, but does have field foO
+//
+// ok             x.Foo   !=    Foo
+// misspelled     x.Foo   !=    FoO    type X has no field or method Foo, but does have field FoO
+// unexported     x.Foo   !=    foo    type X has no field or method Foo, but does have unexported field foo
+// missing        x.Foo   !=    foO    type X has no field or method Foo
+//
+// misspelled     x.foo   !=    Foo    type X has no field or method foo, but does have field Foo
+// missing        x.foo   !=    FoO    type X has no field or method foo
+// inaccessible   x.foo   !=    foo    cannot refer to unexported field foo
+// missing        x.foo   !=    foO    type X has no field or method foo
+
+type S struct {
+       Foo1 int
+       FoO2 int
+       foo3 int
+       foO4 int
+}
+
+func _() {
+       var x S
+       _ = x.Foo1 // OK
+       _ = x.Foo2 // ERROR "x.Foo2 undefined (type S has no field or method Foo2, but does have field FoO2)"
+       _ = x.Foo3 // ERROR "x.Foo3 undefined (type S has no field or method Foo3, but does have field foo3)"
+       _ = x.Foo4 // ERROR "x.Foo4 undefined (type S has no field or method Foo4, but does have field foO4)"
+
+       _ = x.foo1 // ERROR "x.foo1 undefined (type S has no field or method foo1, but does have field Foo1)"
+       _ = x.foo2 // ERROR "x.foo2 undefined (type S has no field or method foo2, but does have field FoO2)"
+       _ = x.foo3 // OK
+       _ = x.foo4 // ERROR "x.foo4 undefined (type S has no field or method foo4, but does have field foO4)"
+}
+
+func _() {
+       _ = S{Foo1: 0} // OK
+       _ = S{Foo2 /* ERROR "unknown field Foo2 in struct literal of type S, but does have FoO2" */ : 0}
+       _ = S{Foo3 /* ERROR "unknown field Foo3 in struct literal of type S, but does have foo3" */ : 0}
+       _ = S{Foo4 /* ERROR "unknown field Foo4 in struct literal of type S, but does have foO4" */ : 0}
+
+       _ = S{foo1 /* ERROR "unknown field foo1 in struct literal of type S, but does have Foo1" */ : 0}
+       _ = S{foo2 /* ERROR "unknown field foo2 in struct literal of type S, but does have FoO2" */ : 0}
+       _ = S{foo3: 0} // OK
+       _ = S{foo4 /* ERROR "unknown field foo4 in struct literal of type S, but does have foO4" */ : 0}
+}
+
+// The following tests follow the same pattern as above but operate on an imported type instead of S.
+// Currently our testing framework doesn't make it easy to define an imported package for testing, so
+// instead we use the big.Float and ast.File types as they provide a suitable mix of exported and un-
+// exported fields and methods.
+
+func _() {
+       var x *big.Float
+       _ = x.Neg  // OK
+       _ = x.NeG  // ERROR "x.NeG undefined (type *big.Float has no field or method NeG, but does have method Neg)"
+       _ = x.Form // ERROR "x.Form undefined (type *big.Float has no field or method Form, but does have unexported field form)"
+       _ = x.ForM // ERROR "x.ForM undefined (type *big.Float has no field or method ForM)"
+
+       _ = x.abs  // ERROR "x.abs undefined (type *big.Float has no field or method abs, but does have method Abs)"
+       _ = x.abS  // ERROR "x.abS undefined (type *big.Float has no field or method abS)"
+       _ = x.form // ERROR "x.form undefined (cannot refer to unexported field form)"
+       _ = x.forM // ERROR "x.forM undefined (type *big.Float has no field or method forM)"
+}
+
+func _() {
+       _ = ast.File{Name: nil} // OK
+       _ = ast.File{NamE /* ERROR "unknown field NamE in struct literal of type ast.File, but does have Name" */ : nil}
+       _ = big.Float{Form /* ERROR "unknown field Form in struct literal of type big.Float, but does have unexported form" */ : 0}
+       _ = big.Float{ForM /* ERROR "unknown field ForM in struct literal of type big.Float" */ : 0}
+
+       _ = ast.File{name /* ERROR "unknown field name in struct literal of type ast.File, but does have Name" */ : nil}
+       _ = ast.File{namE /* ERROR "unknown field namE in struct literal of type ast.File" */ : nil}
+       _ = big.Float{form /* ERROR "cannot refer to unexported field form in struct literal of type big.Float" */ : 0}
+       _ = big.Float{forM /* ERROR "unknown field forM in struct literal of type big.Float" */ : 0}
+}
diff --git a/src/internal/types/testdata/fixedbugs/issue49736.go b/src/internal/types/testdata/fixedbugs/issue49736.go
new file mode 100644 (file)
index 0000000..83e53a4
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2024 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 p
+
+import "math/big"
+
+// From go.dev/issue/18419
+func _(x *big.Float) {
+       x.form /* ERROR "x.form undefined (cannot refer to unexported field form)" */ ()
+}
+
+// From go.dev/issue/31053
+func _() {
+       _ = big.Float{form /* ERROR "cannot refer to unexported field form in struct literal of type big.Float" */ : 0}
+}
index 933c83dc5bf21f24beb353677e341bf1a054975a..fb5873e8e57caec7c62285bfaa932d40dfca774d 100644 (file)
@@ -15,7 +15,7 @@ func main() {
        i1 := it{Floats: true}
        if i1.floats { // ERROR "(type it .* field or method floats, but does have field Floats)|undefined field or method"
        }
-       i2 := &it{floats: false} // ERROR "(but does have field Floats)|unknown field|declared and not used"
+       i2 := &it{floats: false} // ERROR "cannot refer to unexported field floats in struct literal|unknown field|declared and not used"
        _ = &it{InneR: "foo"}    // ERROR "(but does have field inner)|unknown field"
        _ = i2
 }
index 06b2e2cac7ddb9f95b379b4dcec9e69fb9cb10ca..27c60a1764a113c6296f9eaac21d116a96801784 100644 (file)
@@ -11,11 +11,11 @@ import "net/http"
 var s = http.Server{}
 var _ = s.doneChan                  // ERROR "s.doneChan undefined .cannot refer to unexported field or method doneChan.$|unexported field or method|s.doneChan undefined"
 var _ = s.DoneChan                  // ERROR "s.DoneChan undefined .type http.Server has no field or method DoneChan.$|undefined field or method"
-var _ = http.Server{tlsConfig: nil} // ERROR "unknown field tlsConfig in struct literal.+ .but does have TLSConfig.$|unknown field .?tlsConfig.? in .?http.Server|unknown field"
+var _ = http.Server{tlsConfig: nil} // ERROR "cannot refer to unexported field tlsConfig in struct literal|unknown field .?tlsConfig.? in .?http.Server|unknown field"
 var _ = http.Server{DoneChan: nil}  // ERROR "unknown field DoneChan in struct literal of type http.Server$|unknown field .?DoneChan.? in .?http.Server"
 
 type foo struct {
        bar int
 }
 
-var _ = &foo{bAr: 10} // ERROR "unknown field bAr in struct literal.+ .but does have bar.$|unknown field .?bAr.? in .?foo|unknown field"
+var _ = &foo{bAr: 10} // ERROR "cannot refer to unexported field bAr in struct literal|unknown field .?bAr.? in .?foo|unknown field"