mirror of
https://github.com/golang/go
synced 2024-09-15 14:10:17 +00:00
[dev.typeparams] cmd/compile: point StructKeyExpr at the types.Field
When constructing struct literals, importers need a way to specify precisely which field to initialize without worrying about visibility or those fields being blank. (A blank field doesn't actually need to be initialized, but the expression needs to be evaluated still, and with the right order-of-operations.) This CL changes StructKeyExpr's Field field to point directly to the corresponding types.Field, rather than merely holding a copy of its Sym and Offset. This is akin to past changes to add SelectorExpr.Selection. Change-Id: I95b72b1788f73206fcebc22b456cf6b1186db6a7 Reviewed-on: https://go-review.googlesource.com/c/go/+/325031 Trust: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
parent
bad388744b
commit
a94e4f5a85
|
@ -324,20 +324,18 @@ func NewKeyExpr(pos src.XPos, key, value Node) *KeyExpr {
|
||||||
// A StructKeyExpr is an Field: Value composite literal key.
|
// A StructKeyExpr is an Field: Value composite literal key.
|
||||||
type StructKeyExpr struct {
|
type StructKeyExpr struct {
|
||||||
miniExpr
|
miniExpr
|
||||||
Field *types.Sym
|
Field *types.Field
|
||||||
Value Node
|
Value Node
|
||||||
Offset int64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStructKeyExpr(pos src.XPos, field *types.Sym, value Node) *StructKeyExpr {
|
func NewStructKeyExpr(pos src.XPos, field *types.Field, value Node) *StructKeyExpr {
|
||||||
n := &StructKeyExpr{Field: field, Value: value}
|
n := &StructKeyExpr{Field: field, Value: value}
|
||||||
n.pos = pos
|
n.pos = pos
|
||||||
n.op = OSTRUCTKEY
|
n.op = OSTRUCTKEY
|
||||||
n.Offset = types.BADWIDTH
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *StructKeyExpr) Sym() *types.Sym { return n.Field }
|
func (n *StructKeyExpr) Sym() *types.Sym { return n.Field.Sym }
|
||||||
|
|
||||||
// An InlinedCallExpr is an inlined function call.
|
// An InlinedCallExpr is an inlined function call.
|
||||||
type InlinedCallExpr struct {
|
type InlinedCallExpr struct {
|
||||||
|
|
|
@ -355,11 +355,13 @@ func (g *irgen) compLit(typ types2.Type, lit *syntax.CompositeLit) ir.Node {
|
||||||
for i, elem := range lit.ElemList {
|
for i, elem := range lit.ElemList {
|
||||||
switch elem := elem.(type) {
|
switch elem := elem.(type) {
|
||||||
case *syntax.KeyValueExpr:
|
case *syntax.KeyValueExpr:
|
||||||
|
var key ir.Node
|
||||||
if isStruct {
|
if isStruct {
|
||||||
exprs[i] = ir.NewStructKeyExpr(g.pos(elem), g.name(elem.Key.(*syntax.Name)), g.expr(elem.Value))
|
key = ir.NewIdent(g.pos(elem.Key), g.name(elem.Key.(*syntax.Name)))
|
||||||
} else {
|
} else {
|
||||||
exprs[i] = ir.NewKeyExpr(g.pos(elem), g.expr(elem.Key), g.expr(elem.Value))
|
key = g.expr(elem.Key)
|
||||||
}
|
}
|
||||||
|
exprs[i] = ir.NewKeyExpr(g.pos(elem), key, g.expr(elem.Value))
|
||||||
default:
|
default:
|
||||||
exprs[i] = g.expr(elem)
|
exprs[i] = g.expr(elem)
|
||||||
}
|
}
|
||||||
|
|
|
@ -937,9 +937,7 @@ func transformCompLit(n *ir.CompLitExpr) (res ir.Node) {
|
||||||
|
|
||||||
f := t.Field(i)
|
f := t.Field(i)
|
||||||
n1 = assignconvfn(n1, f.Type)
|
n1 = assignconvfn(n1, f.Type)
|
||||||
sk := ir.NewStructKeyExpr(base.Pos, f.Sym, n1)
|
ls[i] = ir.NewStructKeyExpr(base.Pos, f, n1)
|
||||||
sk.Offset = f.Offset
|
|
||||||
ls[i] = sk
|
|
||||||
}
|
}
|
||||||
assert(len(ls) >= t.NumFields())
|
assert(len(ls) >= t.NumFields())
|
||||||
} else {
|
} else {
|
||||||
|
@ -948,7 +946,6 @@ func transformCompLit(n *ir.CompLitExpr) (res ir.Node) {
|
||||||
for i, l := range ls {
|
for i, l := range ls {
|
||||||
ir.SetPos(l)
|
ir.SetPos(l)
|
||||||
|
|
||||||
if l.Op() == ir.OKEY {
|
|
||||||
kv := l.(*ir.KeyExpr)
|
kv := l.(*ir.KeyExpr)
|
||||||
key := kv.Key
|
key := kv.Key
|
||||||
|
|
||||||
|
@ -966,15 +963,9 @@ func transformCompLit(n *ir.CompLitExpr) (res ir.Node) {
|
||||||
// is never a valid struct literal key.
|
// is never a valid struct literal key.
|
||||||
assert(!(s == nil || s.Pkg != types.LocalPkg || key.Op() == ir.OXDOT || s.IsBlank()))
|
assert(!(s == nil || s.Pkg != types.LocalPkg || key.Op() == ir.OXDOT || s.IsBlank()))
|
||||||
|
|
||||||
l = ir.NewStructKeyExpr(l.Pos(), s, kv.Value)
|
f := typecheck.Lookdot1(nil, s, t, t.Fields(), 0)
|
||||||
|
l := ir.NewStructKeyExpr(l.Pos(), f, kv.Value)
|
||||||
ls[i] = l
|
ls[i] = l
|
||||||
}
|
|
||||||
|
|
||||||
assert(l.Op() == ir.OSTRUCTKEY)
|
|
||||||
l := l.(*ir.StructKeyExpr)
|
|
||||||
|
|
||||||
f := typecheck.Lookdot1(nil, l.Field, t, t.Fields(), 0)
|
|
||||||
l.Offset = f.Offset
|
|
||||||
|
|
||||||
l.Value = assignconvfn(l.Value, f.Type)
|
l.Value = assignconvfn(l.Value, f.Type)
|
||||||
}
|
}
|
||||||
|
|
|
@ -403,10 +403,10 @@ func (s *Schedule) initplan(n ir.Node) {
|
||||||
base.Fatalf("initplan structlit")
|
base.Fatalf("initplan structlit")
|
||||||
}
|
}
|
||||||
a := a.(*ir.StructKeyExpr)
|
a := a.(*ir.StructKeyExpr)
|
||||||
if a.Field.IsBlank() {
|
if a.Sym().IsBlank() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
s.addvalue(p, a.Offset, a.Value)
|
s.addvalue(p, a.Field.Offset, a.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
case ir.OMAPLIT:
|
case ir.OMAPLIT:
|
||||||
|
|
|
@ -327,9 +327,7 @@ func tcCompLit(n *ir.CompLitExpr) (res ir.Node) {
|
||||||
}
|
}
|
||||||
// No pushtype allowed here. Must name fields for that.
|
// No pushtype allowed here. Must name fields for that.
|
||||||
n1 = AssignConv(n1, f.Type, "field value")
|
n1 = AssignConv(n1, f.Type, "field value")
|
||||||
sk := ir.NewStructKeyExpr(base.Pos, f.Sym, n1)
|
ls[i] = ir.NewStructKeyExpr(base.Pos, f, n1)
|
||||||
sk.Offset = f.Offset
|
|
||||||
ls[i] = sk
|
|
||||||
}
|
}
|
||||||
if len(ls) < t.NumFields() {
|
if len(ls) < t.NumFields() {
|
||||||
base.Errorf("too few values in %v", n)
|
base.Errorf("too few values in %v", n)
|
||||||
|
@ -339,77 +337,33 @@ func tcCompLit(n *ir.CompLitExpr) (res ir.Node) {
|
||||||
|
|
||||||
// keyed list
|
// keyed list
|
||||||
ls := n.List
|
ls := n.List
|
||||||
for i, l := range ls {
|
for i, n := range ls {
|
||||||
ir.SetPos(l)
|
ir.SetPos(n)
|
||||||
|
|
||||||
if l.Op() == ir.OKEY {
|
sk, ok := n.(*ir.StructKeyExpr)
|
||||||
kv := l.(*ir.KeyExpr)
|
if !ok {
|
||||||
key := kv.Key
|
kv, ok := n.(*ir.KeyExpr)
|
||||||
|
if !ok {
|
||||||
// Sym might have resolved to name in other top-level
|
|
||||||
// package, because of import dot. Redirect to correct sym
|
|
||||||
// before we do the lookup.
|
|
||||||
s := key.Sym()
|
|
||||||
if id, ok := key.(*ir.Ident); ok && DotImportRefs[id] != nil {
|
|
||||||
s = Lookup(s.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// An OXDOT uses the Sym field to hold
|
|
||||||
// the field to the right of the dot,
|
|
||||||
// so s will be non-nil, but an OXDOT
|
|
||||||
// is never a valid struct literal key.
|
|
||||||
if s == nil || s.Pkg != types.LocalPkg || key.Op() == ir.OXDOT || s.IsBlank() {
|
|
||||||
base.Errorf("invalid field name %v in struct initializer", key)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
l = ir.NewStructKeyExpr(l.Pos(), s, kv.Value)
|
|
||||||
ls[i] = l
|
|
||||||
}
|
|
||||||
|
|
||||||
if l.Op() != ir.OSTRUCTKEY {
|
|
||||||
if !errored {
|
if !errored {
|
||||||
base.Errorf("mixture of field:value and value initializers")
|
base.Errorf("mixture of field:value and value initializers")
|
||||||
errored = true
|
errored = true
|
||||||
}
|
}
|
||||||
ls[i] = Expr(ls[i])
|
ls[i] = Expr(n)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
l := l.(*ir.StructKeyExpr)
|
|
||||||
|
|
||||||
f := Lookdot1(nil, l.Field, t, t.Fields(), 0)
|
sk = tcStructLitKey(t, kv)
|
||||||
if f == nil {
|
if sk == nil {
|
||||||
if ci := Lookdot1(nil, l.Field, t, t.Fields(), 2); ci != nil { // Case-insensitive lookup.
|
|
||||||
if visible(ci.Sym) {
|
|
||||||
base.Errorf("unknown field '%v' in struct literal of type %v (but does have %v)", l.Field, t, ci.Sym)
|
|
||||||
} else if nonexported(l.Field) && l.Field.Name == ci.Sym.Name { // Ensure exactness before the suggestion.
|
|
||||||
base.Errorf("cannot refer to unexported field '%v' in struct literal of type %v", l.Field, t)
|
|
||||||
} else {
|
|
||||||
base.Errorf("unknown field '%v' in struct literal of type %v", l.Field, t)
|
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var f *types.Field
|
|
||||||
p, _ := dotpath(l.Field, t, &f, true)
|
fielddup(sk.Sym().Name, hash)
|
||||||
if p == nil || f.IsMethod() {
|
|
||||||
base.Errorf("unknown field '%v' in struct literal of type %v", l.Field, t)
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
// dotpath returns the parent embedded types in reverse order.
|
|
||||||
var ep []string
|
|
||||||
for ei := len(p) - 1; ei >= 0; ei-- {
|
|
||||||
ep = append(ep, p[ei].field.Sym.Name)
|
|
||||||
}
|
|
||||||
ep = append(ep, l.Field.Name)
|
|
||||||
base.Errorf("cannot use promoted field %v in struct literal of type %v", strings.Join(ep, "."), t)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fielddup(f.Sym.Name, hash)
|
|
||||||
l.Offset = f.Offset
|
|
||||||
|
|
||||||
// No pushtype allowed here. Tried and rejected.
|
// No pushtype allowed here. Tried and rejected.
|
||||||
l.Value = Expr(l.Value)
|
sk.Value = Expr(sk.Value)
|
||||||
l.Value = AssignConv(l.Value, f.Type, "field value")
|
sk.Value = AssignConv(sk.Value, sk.Field.Type, "field value")
|
||||||
|
ls[i] = sk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,6 +374,60 @@ func tcCompLit(n *ir.CompLitExpr) (res ir.Node) {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tcStructLitKey typechecks an OKEY node that appeared within a
|
||||||
|
// struct literal.
|
||||||
|
func tcStructLitKey(typ *types.Type, kv *ir.KeyExpr) *ir.StructKeyExpr {
|
||||||
|
key := kv.Key
|
||||||
|
|
||||||
|
// Sym might have resolved to name in other top-level
|
||||||
|
// package, because of import dot. Redirect to correct sym
|
||||||
|
// before we do the lookup.
|
||||||
|
sym := key.Sym()
|
||||||
|
if id, ok := key.(*ir.Ident); ok && DotImportRefs[id] != nil {
|
||||||
|
sym = Lookup(sym.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// An OXDOT uses the Sym field to hold
|
||||||
|
// the field to the right of the dot,
|
||||||
|
// so s will be non-nil, but an OXDOT
|
||||||
|
// is never a valid struct literal key.
|
||||||
|
if sym == nil || sym.Pkg != types.LocalPkg || key.Op() == ir.OXDOT || sym.IsBlank() {
|
||||||
|
base.Errorf("invalid field name %v in struct initializer", key)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if f := Lookdot1(nil, sym, typ, typ.Fields(), 0); f != nil {
|
||||||
|
return ir.NewStructKeyExpr(kv.Pos(), f, kv.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ci := Lookdot1(nil, sym, typ, typ.Fields(), 2); ci != nil { // Case-insensitive lookup.
|
||||||
|
if visible(ci.Sym) {
|
||||||
|
base.Errorf("unknown field '%v' in struct literal of type %v (but does have %v)", sym, typ, ci.Sym)
|
||||||
|
} else if nonexported(sym) && sym.Name == ci.Sym.Name { // Ensure exactness before the suggestion.
|
||||||
|
base.Errorf("cannot refer to unexported field '%v' in struct literal of type %v", sym, typ)
|
||||||
|
} else {
|
||||||
|
base.Errorf("unknown field '%v' in struct literal of type %v", sym, typ)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var f *types.Field
|
||||||
|
p, _ := dotpath(sym, typ, &f, true)
|
||||||
|
if p == nil || f.IsMethod() {
|
||||||
|
base.Errorf("unknown field '%v' in struct literal of type %v", sym, typ)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dotpath returns the parent embedded types in reverse order.
|
||||||
|
var ep []string
|
||||||
|
for ei := len(p) - 1; ei >= 0; ei-- {
|
||||||
|
ep = append(ep, p[ei].field.Sym.Name)
|
||||||
|
}
|
||||||
|
ep = append(ep, sym.Name)
|
||||||
|
base.Errorf("cannot use promoted field %v in struct literal of type %v", strings.Join(ep, "."), typ)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// tcConv typechecks an OCONV node.
|
// tcConv typechecks an OCONV node.
|
||||||
func tcConv(n *ir.ConvExpr) ir.Node {
|
func tcConv(n *ir.ConvExpr) ir.Node {
|
||||||
types.CheckSize(n.Type()) // ensure width is calculated for backend
|
types.CheckSize(n.Type()) // ensure width is calculated for backend
|
||||||
|
|
|
@ -2062,11 +2062,8 @@ func (w *exportWriter) fieldList(list ir.Nodes) {
|
||||||
for _, n := range list {
|
for _, n := range list {
|
||||||
n := n.(*ir.StructKeyExpr)
|
n := n.(*ir.StructKeyExpr)
|
||||||
w.pos(n.Pos())
|
w.pos(n.Pos())
|
||||||
w.selector(n.Field)
|
w.exoticField(n.Field)
|
||||||
w.expr(n.Value)
|
w.expr(n.Value)
|
||||||
if go117ExportTypes {
|
|
||||||
w.uint64(uint64(n.Offset))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1719,11 +1719,7 @@ func (r *importReader) op() ir.Op {
|
||||||
func (r *importReader) fieldList() []ir.Node {
|
func (r *importReader) fieldList() []ir.Node {
|
||||||
list := make([]ir.Node, r.uint64())
|
list := make([]ir.Node, r.uint64())
|
||||||
for i := range list {
|
for i := range list {
|
||||||
x := ir.NewStructKeyExpr(r.pos(), r.selector(), r.expr())
|
list[i] = ir.NewStructKeyExpr(r.pos(), r.exoticField(), r.expr())
|
||||||
if go117ExportTypes {
|
|
||||||
x.Offset = int64(r.uint64())
|
|
||||||
}
|
|
||||||
list[i] = x
|
|
||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,6 +122,9 @@ func walkClosure(clo *ir.ClosureExpr, init *ir.Nodes) ir.Node {
|
||||||
clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ), nil)
|
clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ), nil)
|
||||||
clos.SetEsc(clo.Esc())
|
clos.SetEsc(clo.Esc())
|
||||||
clos.List = append([]ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, clofn.Nname)}, closureArgs(clo)...)
|
clos.List = append([]ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, clofn.Nname)}, closureArgs(clo)...)
|
||||||
|
for i, value := range clos.List {
|
||||||
|
clos.List[i] = ir.NewStructKeyExpr(base.Pos, typ.Field(i), value)
|
||||||
|
}
|
||||||
|
|
||||||
addr := typecheck.NodAddr(clos)
|
addr := typecheck.NodAddr(clos)
|
||||||
addr.SetEsc(clo.Esc())
|
addr.SetEsc(clo.Esc())
|
||||||
|
|
|
@ -218,11 +218,11 @@ func fixedlit(ctxt initContext, kind initKind, n *ir.CompLitExpr, var_ ir.Node,
|
||||||
case ir.OSTRUCTLIT:
|
case ir.OSTRUCTLIT:
|
||||||
splitnode = func(rn ir.Node) (ir.Node, ir.Node) {
|
splitnode = func(rn ir.Node) (ir.Node, ir.Node) {
|
||||||
r := rn.(*ir.StructKeyExpr)
|
r := rn.(*ir.StructKeyExpr)
|
||||||
if r.Field.IsBlank() || isBlank {
|
if r.Sym().IsBlank() || isBlank {
|
||||||
return ir.BlankNode, r.Value
|
return ir.BlankNode, r.Value
|
||||||
}
|
}
|
||||||
ir.SetPos(r)
|
ir.SetPos(r)
|
||||||
return ir.NewSelectorExpr(base.Pos, ir.ODOT, var_, r.Field), r.Value
|
return ir.NewSelectorExpr(base.Pos, ir.ODOT, var_, r.Sym()), r.Value
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
base.Fatalf("fixedlit bad op: %v", n.Op())
|
base.Fatalf("fixedlit bad op: %v", n.Op())
|
||||||
|
|
Loading…
Reference in a new issue