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:
Robert Griesemer
2026-03-16 14:01:37 -07:00
committed by Gopher Robot
parent 9ec1d8f335
commit 30bfe53dd7
4 changed files with 55 additions and 6 deletions

View File

@@ -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

View File

@@ -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
}

View File

@@ -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
View 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))
}
}