mirror of
https://github.com/golang/go.git
synced 2026-04-02 09:20:29 +09:00
cmd/compile/internal/noder: encode promoted struct fields for composite literals in UIR
This change requires an encoding format change for struct literals. Introduce a new UIR version (V3) and use the opportunity to encode all composite literals more compactly: specifically, when we know that (composite literal) keys are always present, avoid encoding a bool value for each key. Do not yet enable the new format. For #9859. Change-Id: Ic6dc9adb1aa494e923eadaf578f8cfc61efd5ea4 Reviewed-on: https://go-review.googlesource.com/c/go/+/754664 Reviewed-by: Mark Freeman <markfreeman@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
@@ -3028,21 +3028,37 @@ func (r *reader) compLit() ir.Node {
|
||||
if typ.IsMap() {
|
||||
rtype = r.rtype(pos)
|
||||
}
|
||||
isStruct := typ.Kind() == types.TSTRUCT
|
||||
|
||||
elems := make([]ir.Node, r.Len())
|
||||
for i := range elems {
|
||||
elemp := &elems[i]
|
||||
|
||||
if isStruct {
|
||||
sk := ir.NewStructKeyExpr(r.pos(), typ.Field(r.Len()), nil)
|
||||
*elemp, elemp = sk, &sk.Value
|
||||
} else if r.Bool() {
|
||||
kv := ir.NewKeyExpr(r.pos(), r.expr(), nil)
|
||||
*elemp, elemp = kv, &kv.Value
|
||||
var elems []ir.Node
|
||||
if r.Version().Has(pkgbits.CompactCompLiterals) {
|
||||
n := r.Int()
|
||||
elems = make([]ir.Node, max(n, -n) /* abs(n) */)
|
||||
switch typ.Kind() {
|
||||
default:
|
||||
base.FatalfAt(pos, "unexpected composite literal type: %v", typ)
|
||||
case types.TARRAY:
|
||||
r.arrayElems(n >= 0, elems)
|
||||
case types.TMAP:
|
||||
r.mapElems(elems)
|
||||
case types.TSLICE:
|
||||
r.arrayElems(n >= 0, elems)
|
||||
case types.TSTRUCT:
|
||||
r.structElems(typ, n >= 0, elems)
|
||||
}
|
||||
} else {
|
||||
elems = make([]ir.Node, r.Len())
|
||||
isStruct := typ.Kind() == types.TSTRUCT
|
||||
for i := range elems {
|
||||
elemp := &elems[i]
|
||||
if isStruct {
|
||||
sk := ir.NewStructKeyExpr(r.pos(), typ.Field(r.Len()), nil)
|
||||
*elemp, elemp = sk, &sk.Value
|
||||
} else if r.Bool() {
|
||||
kv := ir.NewKeyExpr(r.pos(), r.expr(), nil)
|
||||
*elemp, elemp = kv, &kv.Value
|
||||
}
|
||||
*elemp = r.expr()
|
||||
}
|
||||
|
||||
*elemp = r.expr()
|
||||
}
|
||||
|
||||
lit := typecheck.Expr(ir.NewCompLitExpr(pos, ir.OCOMPLIT, typ, elems))
|
||||
@@ -3057,6 +3073,63 @@ func (r *reader) compLit() ir.Node {
|
||||
return lit
|
||||
}
|
||||
|
||||
func (r *reader) arrayElems(valuesOnly bool, elems []ir.Node) {
|
||||
if valuesOnly {
|
||||
for i := range elems {
|
||||
elems[i] = r.expr()
|
||||
}
|
||||
return
|
||||
}
|
||||
// some elements may have a key
|
||||
for i := range elems {
|
||||
if r.Bool() {
|
||||
kv := ir.NewKeyExpr(r.pos(), r.expr(), nil)
|
||||
kv.Value = r.expr()
|
||||
elems[i] = kv
|
||||
} else {
|
||||
elems[i] = r.expr()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *reader) mapElems(elems []ir.Node) {
|
||||
// all elements have a key
|
||||
for i := range elems {
|
||||
kv := ir.NewKeyExpr(r.pos(), r.expr(), nil)
|
||||
kv.Value = r.expr()
|
||||
elems[i] = kv
|
||||
}
|
||||
}
|
||||
|
||||
func (r *reader) structElems(typ *types.Type, valuesOnly bool, elems []ir.Node) {
|
||||
if valuesOnly {
|
||||
for i := range elems {
|
||||
sk := ir.NewStructKeyExpr(r.pos(), typ.Field(i), nil)
|
||||
sk.Value = r.expr()
|
||||
elems[i] = sk
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// all elements have a key
|
||||
for i := range elems {
|
||||
pos := r.pos()
|
||||
var fld *types.Field
|
||||
if n := r.Int(); n < 0 {
|
||||
// embedded field
|
||||
for range -n {
|
||||
fld = typ.Field(r.Int())
|
||||
typ = fld.Type
|
||||
}
|
||||
} else { // n >= 0
|
||||
fld = typ.Field(n)
|
||||
}
|
||||
sk := ir.NewStructKeyExpr(pos, fld, nil)
|
||||
sk.Value = r.expr()
|
||||
elems[i] = sk
|
||||
}
|
||||
}
|
||||
|
||||
func (r *reader) funcLit() ir.Node {
|
||||
r.Sync(pkgbits.SyncFuncLit)
|
||||
|
||||
|
||||
@@ -2344,6 +2344,25 @@ func (w *writer) compLit(lit *syntax.CompositeLit) {
|
||||
if ptr, ok := types2.CoreType(typ).(*types2.Pointer); ok {
|
||||
typ = ptr.Elem()
|
||||
}
|
||||
|
||||
if w.Version().Has(pkgbits.CompactCompLiterals) {
|
||||
switch typ0 := typ; typ := types2.CoreType(typ).(type) {
|
||||
default:
|
||||
w.p.fatalf(lit, "unexpected composite literal type: %v", typ)
|
||||
case *types2.Array:
|
||||
w.arrayElems(typ.Elem(), lit.ElemList)
|
||||
case *types2.Map:
|
||||
w.rtype(typ0)
|
||||
w.mapElems(typ.Key(), typ.Elem(), lit.ElemList)
|
||||
case *types2.Slice:
|
||||
w.arrayElems(typ.Elem(), lit.ElemList)
|
||||
case *types2.Struct:
|
||||
w.structElems(typ, lit.NKeys == 0, lit.ElemList)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// old format
|
||||
var keyType, elemType types2.Type
|
||||
var structType *types2.Struct
|
||||
switch typ0 := typ; typ := types2.CoreType(typ).(type) {
|
||||
@@ -2386,6 +2405,76 @@ func (w *writer) compLit(lit *syntax.CompositeLit) {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *writer) arrayElems(elemType types2.Type, elems []syntax.Expr) {
|
||||
valuesOnly := true
|
||||
for _, elem := range elems {
|
||||
if _, ok := elem.(*syntax.KeyValueExpr); ok {
|
||||
valuesOnly = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if valuesOnly {
|
||||
w.Int(len(elems))
|
||||
for _, elem := range elems {
|
||||
w.implicitConvExpr(elemType, elem)
|
||||
}
|
||||
return
|
||||
}
|
||||
// some elements may have a key
|
||||
w.Int(-len(elems))
|
||||
for _, elem := range elems {
|
||||
if kv, ok := elem.(*syntax.KeyValueExpr); w.Bool(ok) {
|
||||
w.pos(kv.Key) // use position of Key rather than of elem (which has position of ':')
|
||||
w.implicitConvExpr(nil, kv.Key)
|
||||
elem = kv.Value
|
||||
}
|
||||
w.implicitConvExpr(elemType, elem)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *writer) mapElems(keyType, valueType types2.Type, elems []syntax.Expr) {
|
||||
// all elements have a key
|
||||
w.Int(-len(elems))
|
||||
for _, elem := range elems {
|
||||
kv := elem.(*syntax.KeyValueExpr)
|
||||
w.pos(kv.Key) // use position of Key rather than of elem (which has position of ':')
|
||||
w.implicitConvExpr(keyType, kv.Key)
|
||||
w.implicitConvExpr(valueType, kv.Value)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *writer) structElems(typ *types2.Struct, valuesOnly bool, elems []syntax.Expr) {
|
||||
n := len(elems)
|
||||
if valuesOnly {
|
||||
// no element has a key
|
||||
w.Int(n)
|
||||
for i, elem := range elems {
|
||||
w.pos(elem)
|
||||
w.implicitConvExpr(typ.Field(i).Type(), elem)
|
||||
}
|
||||
return
|
||||
}
|
||||
// all elements have a key
|
||||
w.Int(-n)
|
||||
for _, elem := range elems {
|
||||
kv := elem.(*syntax.KeyValueExpr)
|
||||
w.pos(kv.Key) // use position of Key rather than of elem (which has position of ':')
|
||||
// TODO(gri): rather than doing this lookup again, perhaps the index should be recorded by types2
|
||||
fld, index, _ := types2.LookupFieldOrMethod(typ, false, w.p.curpkg, kv.Key.(*syntax.Name).Value)
|
||||
if n := len(index); n > 1 {
|
||||
// embedded field
|
||||
w.Int(-n)
|
||||
for _, i := range index {
|
||||
w.Int(i)
|
||||
}
|
||||
} else { // n == 1
|
||||
w.Int(index[0])
|
||||
}
|
||||
w.implicitConvExpr(fld.Type(), kv.Value)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *writer) funcLit(expr *syntax.FuncLit) {
|
||||
sig := w.p.typeOf(expr).(*types2.Signature)
|
||||
|
||||
|
||||
@@ -28,6 +28,12 @@ const (
|
||||
// - remove derived info "needed" bool
|
||||
V2
|
||||
|
||||
// V3: introduces a more compact format for composite literal element lists
|
||||
// - negative lengths indicate that (some) elements may have keys
|
||||
// - positive lengths indicate that no element has a key
|
||||
// - a negative struct field index indicates an embedded field
|
||||
V3
|
||||
|
||||
numVersions = iota
|
||||
)
|
||||
|
||||
@@ -61,6 +67,9 @@ const (
|
||||
// whether a type was a derived type.
|
||||
DerivedInfoNeeded
|
||||
|
||||
// Composite literals use a more compact format for element lists.
|
||||
CompactCompLiterals
|
||||
|
||||
numFields = iota
|
||||
)
|
||||
|
||||
@@ -68,6 +77,7 @@ const (
|
||||
var introduced = [numFields]Version{
|
||||
Flags: V1,
|
||||
AliasTypeParamNames: V2,
|
||||
CompactCompLiterals: V3,
|
||||
}
|
||||
|
||||
// removed is the version a field was removed in or 0 for fields
|
||||
|
||||
Reference in New Issue
Block a user