Skip to content

Commit 8e51a5f

Browse files
committed
go/ssa: support direct references to embedded fields in struct lit
For golang/go#78553 Change-Id: If5a8fbeecefd13cd27848abea981fa95ff5a5d18 Reviewed-on: https://go-review.googlesource.com/c/tools/+/763920 Reviewed-by: Alan Donovan <adonovan@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
1 parent 5005b9e commit 8e51a5f

4 files changed

Lines changed: 93 additions & 17 deletions

File tree

go/ssa/builder.go

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,7 +1275,7 @@ func (b *builder) arrayLen(fn *Function, elts []ast.Expr) int64 {
12751275
// x := T{a: 1}
12761276
// x = T{a: x.a}
12771277
//
1278-
// all the reads must occur before all the writes. Thus all stores to
1278+
// all the reads must occur before all the writes. Thus all stores to
12791279
// loc are emitted to the storebuf sb for later execution.
12801280
//
12811281
// A CompositeLit may have pointer type only in the recursive (nested)
@@ -1292,28 +1292,35 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero
12921292
sb.store(&address{addr, e.Lbrace, nil}, zeroConst(zt))
12931293
isZero = true
12941294
}
1295+
var fIndices []int
12951296
for i, e := range e.Elts {
1296-
fieldIndex := i
1297-
pos := e.Pos()
1298-
if kv, ok := e.(*ast.KeyValueExpr); ok {
1297+
var (
1298+
pos token.Pos
1299+
fType types.Type
1300+
)
1301+
1302+
if kv, ok := e.(*ast.KeyValueExpr); ok { // tagged field
12991303
fname := kv.Key.(*ast.Ident).Name
1300-
for i, n := 0, t.NumFields(); i < n; i++ {
1301-
sf := t.Field(i)
1302-
if sf.Name() == fname {
1303-
fieldIndex = i
1304-
pos = kv.Colon
1305-
e = kv.Value
1306-
break
1307-
}
1308-
}
1304+
obj, index, _ := types.LookupFieldOrMethod(t, true, fn.declaredPackage().Pkg, fname)
1305+
fIndices = append(fIndices[:0], index...)
1306+
pos = kv.Colon
1307+
e = kv.Value
1308+
fType = obj.Type()
1309+
} else { // untagged field
1310+
fIndices = append(fIndices[:0], i)
1311+
pos = e.Pos()
1312+
fType = t.Field(i).Type()
13091313
}
1310-
sf := t.Field(fieldIndex)
1314+
1315+
last := len(fIndices) - 1
1316+
v := emitImplicitSelections(fn, addr, fIndices[:last], pos)
1317+
13111318
faddr := &FieldAddr{
1312-
X: addr,
1313-
Field: fieldIndex,
1319+
X: v,
1320+
Field: fIndices[last],
13141321
}
13151322
faddr.setPos(pos)
1316-
faddr.setType(types.NewPointer(sf.Type()))
1323+
faddr.setType(types.NewPointer(fType))
13171324
fn.emit(faddr)
13181325
b.assign(fn, &address{addr: faddr, pos: pos, expr: e}, e, isZero, sb)
13191326
}

go/ssa/interp/interp_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ var testdataTests = []string{
141141
"slice2array.go",
142142
"slice2arrayptr.go",
143143
"static.go",
144+
"structlitpromoted_go127.go",
144145
"typeassert.go",
145146
"width32.go",
146147
"zeros.go",
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2026 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build go1.27
6+
7+
package main
8+
9+
func main() {
10+
// Test direct initialization of promoted fields in struct literals,
11+
// introduced in go1.27. See golang/go#9859.
12+
type Inner struct {
13+
X int
14+
}
15+
type Outer struct {
16+
Inner
17+
Y int
18+
}
19+
20+
o := Outer{
21+
X: 1,
22+
Y: 2,
23+
}
24+
25+
if o.X != 1 || o.Y != 2 {
26+
panic("failed to initialize promoted field")
27+
}
28+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// This test verifies that hover works correctly on promoted fields
2+
// in struct composite literals (a Go 1.27 feature).
3+
4+
-- flags --
5+
-min_go_command=go1.27
6+
7+
-- go.mod --
8+
module mod.com
9+
10+
go 1.27
11+
-- main.go --
12+
package main
13+
14+
type E1 struct {
15+
A int
16+
}
17+
18+
type T struct {
19+
E1
20+
}
21+
22+
func main() {
23+
_ = T{
24+
A: 1,//@ hover("A", "A", a)
25+
}
26+
27+
_ = T{
28+
E1: E1{
29+
A: 1,//@ hover("A", "A", a)
30+
},
31+
}
32+
}
33+
-- @a --
34+
```go
35+
field A int
36+
```
37+
38+
---
39+
40+
[`(main.E1).A` on pkg.go.dev](https://pkg.go.dev/mod.com#E1.A)

0 commit comments

Comments
 (0)