go/types, types2: use consistent error messages for invalid struct literals

Fixes #51879.

Change-Id: Ic7ac892b82a0fe4ad6f95ff8ae84e6d30c52c111
Reviewed-on: https://go-review.googlesource.com/c/go/+/438855
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Robert Griesemer 2022-10-04 18:18:01 -07:00 committed by Gopher Robot
parent 47a538842b
commit 97d38f3002
4 changed files with 17 additions and 11 deletions

View File

@ -1385,6 +1385,9 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
if len(e.ElemList) == 0 {
break
}
// Convention for error messages on invalid struct literals:
// we mention the struct type only if it clarifies the error
// (e.g., a duplicate field error doesn't need the struct type).
fields := utyp.fields
if _, ok := e.ElemList[0].(*syntax.KeyValueExpr); ok {
// all elements must have keys
@ -1428,20 +1431,20 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
}
check.expr(x, e)
if i >= len(fields) {
check.errorf(x, _InvalidStructLit, "too many values in %s{…}", base)
check.errorf(x, _InvalidStructLit, "too many values in struct literal of type %s", base)
break // cannot continue
}
// i < len(fields)
fld := fields[i]
if !fld.Exported() && fld.pkg != check.pkg {
check.errorf(x, _UnexportedLitField, "implicit assignment to unexported field %s in %s literal", fld.name, typ)
check.errorf(x, _UnexportedLitField, "implicit assignment to unexported field %s in struct literal of type %s", fld.name, base)
continue
}
etyp := fld.typ
check.assignment(x, etyp, "struct literal")
}
if len(e.ElemList) < len(fields) {
check.errorf(e.Rbrace, _InvalidStructLit, "too few values in %s{…}", base)
check.errorf(e.Rbrace, _InvalidStructLit, "too few values in struct literal of type %s", base)
// ok to continue
}
}

View File

@ -1364,6 +1364,9 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
if len(e.Elts) == 0 {
break
}
// Convention for error messages on invalid struct literals:
// we mention the struct type only if it clarifies the error
// (e.g., a duplicate field error doesn't need the struct type).
fields := utyp.fields
if _, ok := e.Elts[0].(*ast.KeyValueExpr); ok {
// all elements must have keys
@ -1407,7 +1410,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
}
check.expr(x, e)
if i >= len(fields) {
check.errorf(x, _InvalidStructLit, "too many values in %s{…}", base)
check.errorf(x, _InvalidStructLit, "too many values in struct literal of type %s", base)
break // cannot continue
}
// i < len(fields)
@ -1415,14 +1418,14 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
if !fld.Exported() && fld.pkg != check.pkg {
check.errorf(x,
_UnexportedLitField,
"implicit assignment to unexported field %s in %s literal", fld.name, typ)
"implicit assignment to unexported field %s in struct literal of type %s", fld.name, base)
continue
}
etyp := fld.typ
check.assignment(x, etyp, "struct literal")
}
if len(e.Elts) < len(fields) {
check.errorf(inNode(e, e.Rbrace), _InvalidStructLit, "too few values in %s{…}", base)
check.errorf(inNode(e, e.Rbrace), _InvalidStructLit, "too few values in struct literal of type %s", base)
// ok to continue
}
}

View File

@ -209,7 +209,7 @@ func struct_literals() {
_ = time.Time{}
_ = time.Time{sec /* ERROR "unknown field" */ : 0}
_ = time.Time{
0 /* ERROR implicit assignment to unexported field wall in time.Time literal */,
0 /* ERROR implicit assignment to unexported field wall in struct literal */,
0 /* ERROR implicit assignment */ ,
nil /* ERROR implicit assignment */ ,
}

View File

@ -10,9 +10,9 @@ type S struct {
}
var (
_ = S{0} /* ERROR too few values in S{…} */
_ = struct{ f1, f2 int }{0} /* ERROR too few values in struct{f1 int; f2 int}{…} */
_ = S{0} /* ERROR too few values in struct literal */
_ = struct{ f1, f2 int }{0} /* ERROR too few values in struct literal */
_ = S{0, true, "foo" /* ERROR too many values in S{…} */}
_ = struct{ f1, f2 int }{0, 1, 2 /* ERROR too many values in struct{f1 int; f2 int}{…} */}
_ = S{0, true, "foo" /* ERROR too many values in struct literal */}
_ = struct{ f1, f2 int }{0, 1, 2 /* ERROR too many values in struct literal */}
)