Skip to content

Commit a5866eb

Browse files
cuonglmgopherbot
authored andcommitted
cmd/compile: prevent shapifying of pointer shape type
CL 641955 changes the Unified IR reader to not doing shapify when reading reshaping expression, prevent losing of the original type. This is an oversight, as the main problem isn't about shaping during the reshaping process itself, but about the specific case of shaping a pointer shape type. This bug occurs when instantiating a generic function within another generic function with a pointer shape type as type parameter, which will convert `*[]go.shape.T` to `*go.shape.uint8`, resulting in the loss of the original expression's type. This commit changes Unified IR reader to avoid pointer shaping for `*[]go.shape.T`, ensures that the original type is preserved when processing reshaping expressions. Updates golang#71184 Updates golang#73947 Fixes golang#74260 Fixes golang#75461 Change-Id: Icede6b73247d0d367bb485619f2dafb60ad66806 Reviewed-on: https://go-review.googlesource.com/c/go/+/704095 Auto-Submit: Cuong Manh Le <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: David Chase <[email protected]> Reviewed-by: Junyang Shao <[email protected]>
1 parent a27261c commit a5866eb

File tree

2 files changed

+91
-33
lines changed

2 files changed

+91
-33
lines changed

src/cmd/compile/internal/noder/reader.go

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@ type pkgReader struct {
4949
// but bitwise inverted so we can detect if we're missing the entry
5050
// or not.
5151
newindex []index
52-
53-
// indicates whether the data is reading during reshaping.
54-
reshaping bool
5552
}
5653

5754
func newPkgReader(pr pkgbits.PkgDecoder) *pkgReader {
@@ -119,10 +116,6 @@ type reader struct {
119116
// find parameters/results.
120117
funarghack bool
121118

122-
// reshaping is used during reading exprReshape code, preventing
123-
// the reader from shapifying the re-shaped type.
124-
reshaping bool
125-
126119
// methodSym is the name of method's name, if reading a method.
127120
// It's nil if reading a normal function or closure body.
128121
methodSym *types.Sym
@@ -937,8 +930,19 @@ func shapify(targ *types.Type, basic bool) *types.Type {
937930
// types, and discarding struct field names and tags. However, we'll
938931
// need to start tracking how type parameters are actually used to
939932
// implement some of these optimizations.
933+
pointerShaping := basic && targ.IsPtr() && !targ.Elem().NotInHeap()
934+
// The exception is when the type parameter is a pointer to a type
935+
// which `Type.HasShape()` returns true, but `Type.IsShape()` returns
936+
// false, like `*[]go.shape.T`. This is because the type parameter is
937+
// used to instantiate a generic function inside another generic function.
938+
// In this case, we want to keep the targ as-is, otherwise, we may lose the
939+
// original type after `*[]go.shape.T` is shapified to `*go.shape.uint8`.
940+
// See issue #54535, #71184.
941+
if pointerShaping && !targ.Elem().IsShape() && targ.Elem().HasShape() {
942+
return targ
943+
}
940944
under := targ.Underlying()
941-
if basic && targ.IsPtr() && !targ.Elem().NotInHeap() {
945+
if pointerShaping {
942946
under = types.NewPtr(types.Types[types.TUINT8])
943947
}
944948

@@ -1014,25 +1018,7 @@ func (pr *pkgReader) objDictIdx(sym *types.Sym, idx index, implicits, explicits
10141018
// arguments.
10151019
for i, targ := range dict.targs {
10161020
basic := r.Bool()
1017-
isPointerShape := basic && targ.IsPtr() && !targ.Elem().NotInHeap()
1018-
// We should not do shapify during the reshaping process, see #71184.
1019-
// However, this only matters for shapify a pointer type, which will
1020-
// lose the original underlying type.
1021-
//
1022-
// Example with a pointer type:
1023-
//
1024-
// - First, shapifying *[]T -> *uint8
1025-
// - During the reshaping process, *uint8 is shapified to *go.shape.uint8
1026-
// - This ends up with a different type with the original *[]T
1027-
//
1028-
// For a non-pointer type:
1029-
//
1030-
// - int -> go.shape.int
1031-
// - go.shape.int -> go.shape.int
1032-
//
1033-
// We always end up with the identical type.
1034-
canShapify := !pr.reshaping || !isPointerShape
1035-
if dict.shaped && canShapify {
1021+
if dict.shaped {
10361022
dict.targs[i] = shapify(targ, basic)
10371023
}
10381024
}
@@ -2470,10 +2456,7 @@ func (r *reader) expr() (res ir.Node) {
24702456

24712457
case exprReshape:
24722458
typ := r.typ()
2473-
old := r.reshaping
2474-
r.reshaping = true
24752459
x := r.expr()
2476-
r.reshaping = old
24772460

24782461
if types.IdenticalStrict(x.Type(), typ) {
24792462
return x
@@ -2596,10 +2579,7 @@ func (r *reader) funcInst(pos src.XPos) (wrapperFn, baseFn, dictPtr ir.Node) {
25962579
info := r.dict.subdicts[idx]
25972580
explicits := r.p.typListIdx(info.explicits, r.dict)
25982581

2599-
old := r.p.reshaping
2600-
r.p.reshaping = r.reshaping
26012582
baseFn = r.p.objIdx(info.idx, implicits, explicits, true).(*ir.Name)
2602-
r.p.reshaping = old
26032583

26042584
// TODO(mdempsky): Is there a more robust way to get the
26052585
// dictionary pointer type here?
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
go build main.go
2+
! stdout .
3+
! stderr .
4+
5+
-- main.go --
6+
package main
7+
8+
import (
9+
"demo/registry"
10+
)
11+
12+
func main() {
13+
_ = registry.NewUserRegistry()
14+
}
15+
16+
-- go.mod --
17+
module demo
18+
19+
go 1.24
20+
21+
-- model/user.go --
22+
package model
23+
24+
type User struct {
25+
ID int
26+
}
27+
28+
func (c *User) String() string {
29+
return ""
30+
}
31+
32+
-- ordered/map.go --
33+
package ordered
34+
35+
type OrderedMap[K comparable, V any] struct {
36+
m map[K]V
37+
}
38+
39+
func New[K comparable, V any](options ...any) *OrderedMap[K, V] {
40+
orderedMap := &OrderedMap[K, V]{}
41+
return orderedMap
42+
}
43+
44+
-- registry/user.go --
45+
package registry
46+
47+
import (
48+
"demo/model"
49+
"demo/ordered"
50+
)
51+
52+
type baseRegistry = Registry[model.User, *model.User]
53+
54+
type UserRegistry struct {
55+
*baseRegistry
56+
}
57+
58+
type Registry[T any, P PStringer[T]] struct {
59+
m *ordered.OrderedMap[string, P]
60+
}
61+
62+
type PStringer[T any] interface {
63+
*T
64+
String() string
65+
}
66+
67+
func NewRegistry[T any, P PStringer[T]]() *Registry[T, P] {
68+
r := &Registry[T, P]{
69+
m: ordered.New[string, P](),
70+
}
71+
return r
72+
}
73+
74+
func NewUserRegistry() *UserRegistry {
75+
return &UserRegistry{
76+
baseRegistry: NewRegistry[model.User](),
77+
}
78+
}

0 commit comments

Comments
 (0)