mirror of
https://github.com/golang/go.git
synced 2026-04-03 09:49:56 +09:00
cmd/compile: enable promoted field selectors as keys in struct literals
Switch the generated UIR version from V2 to V3. Adjust cmd/compile/internal/types to accept promoted field selectors in composite literals. Fixes #9859. Change-Id: Ie314e28567cfa6cf4c9e962a07b32dd05b06bf5e Reviewed-on: https://go-review.googlesource.com/c/go/+/755740 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Robert Griesemer <gri@google.com> Reviewed-by: Mark Freeman <markfreeman@google.com> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
committed by
Gopher Robot
parent
9ec1d8f335
commit
30bfe53dd7
@@ -25,8 +25,8 @@ import (
|
||||
)
|
||||
|
||||
// uirVersion is the unified IR version to use for encoding/decoding.
|
||||
// Use V2 as the encoded version for aliastypeparams.
|
||||
const uirVersion = pkgbits.V2
|
||||
// Use V3 for promoted struct field support in composite literals.
|
||||
const uirVersion = pkgbits.V3
|
||||
|
||||
// localPkgReader holds the package reader used for reading the local
|
||||
// package. It exists so the unified IR linker can refer back to it
|
||||
|
||||
@@ -312,6 +312,19 @@ func tcStructLitKey(typ *types.Type, kv *ir.KeyExpr) *ir.StructKeyExpr {
|
||||
return ir.NewStructKeyExpr(kv.Pos(), f, kv.Value)
|
||||
}
|
||||
|
||||
var f *types.Field
|
||||
if p, ambig := dotpath(sym, typ, &f, false); p != nil {
|
||||
if ambig {
|
||||
base.Errorf("ambiguous promoted field '%v' in struct literal of type %v", sym, typ)
|
||||
return nil
|
||||
}
|
||||
if f.IsMethod() {
|
||||
base.Errorf("cannot use method '%v' in struct literal of type %v", sym, typ)
|
||||
return 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)
|
||||
@@ -323,7 +336,6 @@ func tcStructLitKey(typ *types.Type, kv *ir.KeyExpr) *ir.StructKeyExpr {
|
||||
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)
|
||||
@@ -335,8 +347,8 @@ func tcStructLitKey(typ *types.Type, kv *ir.KeyExpr) *ir.StructKeyExpr {
|
||||
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)
|
||||
ep = append(ep, f.Sym.Name)
|
||||
base.Errorf("unknown field '%v' in struct literal of type %v (but does have %v)", sym, typ, strings.Join(ep, "."))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -226,7 +226,7 @@ func fixedlit(ctxt initContext, kind initKind, n *ir.CompLitExpr, var_ ir.Node,
|
||||
return ir.BlankNode, r.Value
|
||||
}
|
||||
ir.SetPos(r)
|
||||
return ir.NewSelectorExpr(base.Pos, ir.ODOT, var_, r.Sym()), r.Value
|
||||
return ir.NewSelectorExpr(base.Pos, ir.OXDOT, var_, r.Sym()), r.Value
|
||||
}
|
||||
default:
|
||||
base.Fatalf("fixedlit bad op: %v", n.Op())
|
||||
|
||||
37
test/complit2.go
Normal file
37
test/complit2.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// run
|
||||
|
||||
// Copyright 2026 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.
|
||||
|
||||
// Verify that composite literals using selectors for
|
||||
// embedded fields are assembled correctly.
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type A struct {
|
||||
a int
|
||||
B
|
||||
}
|
||||
|
||||
type B struct {
|
||||
b string
|
||||
C
|
||||
}
|
||||
|
||||
type C struct {
|
||||
c any
|
||||
}
|
||||
|
||||
func main() {
|
||||
eq(A{1, B{b: "foo"}}, A{a: 1, b: "foo"})
|
||||
eq(A{B: B{C: C{c: "foo"}}}, A{c: "foo"})
|
||||
}
|
||||
|
||||
func eq(x, y any) {
|
||||
if x != y {
|
||||
panic(fmt.Sprintf("%v != %v", x, y))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user