Skip to content

Commit d6b60d2

Browse files
committed
metadata: simplify summary accessors
1 parent 3ddbacb commit d6b60d2

6 files changed

Lines changed: 186 additions & 73 deletions

File tree

internal/metadata/format.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@ import (
99

1010
// FormatMeta writes a stable human-readable representation for tests.
1111
func FormatMeta(w io.Writer, pm *PackageMeta) {
12-
if pm == nil {
13-
return
14-
}
15-
1612
sym := func(s Symbol) string {
1713
if int(s) < len(pm.stringTable) {
1814
return pm.stringTable[s]

internal/metadata/global_summary.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,37 +125,37 @@ func (g *GlobalSummary) ConcreteTypes() []Symbol {
125125

126126
// OrdinaryEdges returns direct ordinary references from sym.
127127
func (g *GlobalSummary) OrdinaryEdges(sym Symbol) []Symbol {
128-
return cloneSymbols(g.ordinaryEdges[sym])
128+
return g.ordinaryEdges[sym]
129129
}
130130

131131
// TypeChildren returns child type symbols for typ.
132132
func (g *GlobalSummary) TypeChildren(typ Symbol) []Symbol {
133-
return cloneSymbols(g.typeChildren[typ])
133+
return g.typeChildren[typ]
134134
}
135135

136136
// InterfaceMethods returns the method set for iface.
137137
func (g *GlobalSummary) InterfaceMethods(iface Symbol) []MethodSig {
138-
return cloneMethodSigs(g.interfaceInfo[iface])
138+
return g.interfaceInfo[iface]
139139
}
140140

141141
// UseIface returns concrete types that enter interface semantics from fn.
142142
func (g *GlobalSummary) UseIface(fn Symbol) []Symbol {
143-
return cloneSymbols(g.useIface[fn])
143+
return g.useIface[fn]
144144
}
145145

146146
// UseIfaceMethod returns interface method demands emitted by fn.
147147
func (g *GlobalSummary) UseIfaceMethod(fn Symbol) []IfaceMethodDemand {
148-
return cloneIfaceMethodDemands(g.useIfaceMethod[fn])
148+
return g.useIfaceMethod[fn]
149149
}
150150

151151
// MethodSlots returns ABI method slots for typ.
152152
func (g *GlobalSummary) MethodSlots(typ Symbol) []MethodSlot {
153-
return cloneMethodSlots(g.methodInfo[typ])
153+
return g.methodInfo[typ]
154154
}
155155

156156
// UseNamedMethod returns constant MethodByName names emitted by fn.
157157
func (g *GlobalSummary) UseNamedMethod(fn Symbol) []Name {
158-
return cloneNames(g.useNamedMethod[fn])
158+
return g.useNamedMethod[fn]
159159
}
160160

161161
// HasReflectMethod reports whether fn triggers conservative reflection handling.
@@ -230,7 +230,7 @@ func (b *globalSummaryBuilder) addMethodSlots(typ Symbol, slots []MethodSlot) er
230230
}
231231
return fmt.Errorf("conflicting MethodInfo for %s", b.summary.SymbolName(typ))
232232
}
233-
b.summary.methodInfo[typ] = cloneMethodSlots(slots)
233+
b.summary.methodInfo[typ] = slots
234234
return nil
235235
}
236236

internal/metadata/global_summary_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,63 @@ func TestGlobalSummaryMergesLocalIDsByText(t *testing.T) {
7777
}
7878
}
7979

80+
func TestGlobalSummaryNameLookupsReturnEmptyStringForOutOfRangeIDs(t *testing.T) {
81+
summary, err := NewGlobalSummary([]*PackageMeta{buildGlobalDuplicateFactsPackage()})
82+
if err != nil {
83+
t.Fatalf("NewGlobalSummary: %v", err)
84+
}
85+
86+
if got := summary.SymbolName(Symbol(len(summary.stringTable))); got != "" {
87+
t.Fatalf("SymbolName(out-of-range) = %q, want empty string", got)
88+
}
89+
if got := summary.Name(Name(len(summary.stringTable))); got != "" {
90+
t.Fatalf("Name(out-of-range) = %q, want empty string", got)
91+
}
92+
}
93+
94+
func TestGlobalSummaryDeduplicatesMergedFacts(t *testing.T) {
95+
pkgA := buildGlobalDuplicateFactsPackage()
96+
pkgB := buildGlobalDuplicateFactsPackage()
97+
98+
summary, err := NewGlobalSummary([]*PackageMeta{pkgA, pkgB})
99+
if err != nil {
100+
t.Fatalf("NewGlobalSummary: %v", err)
101+
}
102+
103+
main := mustLookupSymbol(t, summary, "pkg.main")
104+
use := mustLookupSymbol(t, summary, "pkg.use")
105+
typ := mustLookupSymbol(t, summary, "_llgo_pkg.T")
106+
iface := mustLookupSymbol(t, summary, "_llgo_iface$I")
107+
funcType := mustLookupSymbol(t, summary, "_llgo_func$M")
108+
ifn := mustLookupSymbol(t, summary, "pkg.(*T).M")
109+
tfn := mustLookupSymbol(t, summary, "pkg.T.M")
110+
methodNames := summary.UseNamedMethod(use)
111+
if len(methodNames) != 1 {
112+
t.Fatalf("UseNamedMethod len = %d (%#v), want 1", len(methodNames), methodNames)
113+
}
114+
wantSig := MethodSig{Name: methodNames[0], MType: funcType}
115+
116+
if got := summary.OrdinaryEdges(main); !reflect.DeepEqual(got, []Symbol{use}) {
117+
t.Fatalf("OrdinaryEdges(pkg.main) = %#v, want %#v", got, []Symbol{use})
118+
}
119+
if got := summary.TypeChildren(typ); !reflect.DeepEqual(got, []Symbol{funcType}) {
120+
t.Fatalf("TypeChildren(_llgo_pkg.T) = %#v, want %#v", got, []Symbol{funcType})
121+
}
122+
if got := summary.InterfaceMethods(iface); !reflect.DeepEqual(got, []MethodSig{wantSig}) {
123+
t.Fatalf("InterfaceMethods(_llgo_iface$I) = %#v, want %#v", got, []MethodSig{wantSig})
124+
}
125+
if got := summary.UseIface(main); !reflect.DeepEqual(got, []Symbol{typ}) {
126+
t.Fatalf("UseIface(pkg.main) = %#v, want %#v", got, []Symbol{typ})
127+
}
128+
wantDemand := IfaceMethodDemand{Target: iface, Sig: wantSig}
129+
if got := summary.UseIfaceMethod(use); !reflect.DeepEqual(got, []IfaceMethodDemand{wantDemand}) {
130+
t.Fatalf("UseIfaceMethod(pkg.use) = %#v, want %#v", got, []IfaceMethodDemand{wantDemand})
131+
}
132+
if got := summary.MethodSlots(typ); !reflect.DeepEqual(got, []MethodSlot{{Sig: wantSig, IFn: ifn, TFn: tfn}}) {
133+
t.Fatalf("MethodSlots(_llgo_pkg.T) = %#v", got)
134+
}
135+
}
136+
80137
func TestGlobalSummaryRejectsConflictingMethodSlots(t *testing.T) {
81138
pkgA, _ := buildGlobalSummaryPkgB()
82139

@@ -99,6 +156,28 @@ func TestGlobalSummaryRejectsConflictingMethodSlots(t *testing.T) {
99156
}
100157
}
101158

159+
func buildGlobalDuplicateFactsPackage() *PackageMeta {
160+
b := NewBuilder()
161+
main := b.Symbol("pkg.main")
162+
use := b.Symbol("pkg.use")
163+
typ := b.Symbol("_llgo_pkg.T")
164+
iface := b.Symbol("_llgo_iface$I")
165+
methodName := b.Name("M")
166+
funcType := b.Symbol("_llgo_func$M")
167+
ifn := b.Symbol("pkg.(*T).M")
168+
tfn := b.Symbol("pkg.T.M")
169+
sig := MethodSig{Name: methodName, MType: funcType}
170+
171+
b.AddEdge(main, use)
172+
b.AddTypeChild(typ, funcType)
173+
b.AddIfaceEntry(iface, []MethodSig{sig})
174+
b.AddUseIface(main, []Symbol{typ})
175+
b.AddUseIfaceMethod(use, []IfaceMethodDemand{{Target: iface, Sig: sig}})
176+
b.AddUseNamedMethod(use, []Name{methodName})
177+
b.AddMethodInfo(typ, []MethodSlot{{Sig: sig, IFn: ifn, TFn: tfn}})
178+
return b.Build()
179+
}
180+
102181
type globalSummaryRefs struct {
103182
intType Symbol
104183
}

internal/metadata/meta.go

Lines changed: 9 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -56,126 +56,74 @@ func NewPackageMeta(stringTable []string) *PackageMeta {
5656
}
5757
}
5858

59-
// StringTable returns a copy of the package-local string table.
60-
func (pm *PackageMeta) StringTable() []string {
61-
if pm == nil {
62-
return nil
63-
}
64-
return append([]string(nil), pm.stringTable...)
65-
}
66-
6759
// SymbolName returns the string referenced by a Symbol.
6860
func (pm *PackageMeta) SymbolName(sym Symbol) string {
69-
if pm == nil || int(sym) >= len(pm.stringTable) {
61+
if int(sym) >= len(pm.stringTable) {
7062
return ""
7163
}
7264
return pm.stringTable[sym]
7365
}
7466

7567
// Name returns the string referenced by a Name.
7668
func (pm *PackageMeta) Name(ref Name) string {
77-
if pm == nil || int(ref) >= len(pm.stringTable) {
69+
if int(ref) >= len(pm.stringTable) {
7870
return ""
7971
}
8072
return pm.stringTable[ref]
8173
}
8274

8375
// ForEachOrdinaryEdge visits each ordinary reachability edge group.
8476
func (pm *PackageMeta) ForEachOrdinaryEdge(fn func(src Symbol, dsts []Symbol)) {
85-
if pm == nil {
86-
return
87-
}
8877
for src, dsts := range pm.ordinaryEdges {
89-
fn(src, cloneSymbols(dsts))
78+
fn(src, dsts)
9079
}
9180
}
9281

9382
// ForEachTypeChild visits each type-child edge group.
9483
func (pm *PackageMeta) ForEachTypeChild(fn func(parent Symbol, children []Symbol)) {
95-
if pm == nil {
96-
return
97-
}
9884
for parent, children := range pm.typeChildren {
99-
fn(parent, cloneSymbols(children))
85+
fn(parent, children)
10086
}
10187
}
10288

10389
// ForEachInterface visits each interface method set.
10490
func (pm *PackageMeta) ForEachInterface(fn func(iface Symbol, methods []MethodSig)) {
105-
if pm == nil {
106-
return
107-
}
10891
for iface, methods := range pm.interfaceInfo {
109-
fn(iface, cloneMethodSigs(methods))
92+
fn(iface, methods)
11093
}
11194
}
11295

11396
// ForEachUseIface visits each function's concrete types used as interfaces.
11497
func (pm *PackageMeta) ForEachUseIface(fn func(owner Symbol, types []Symbol)) {
115-
if pm == nil {
116-
return
117-
}
11898
for owner, types := range pm.useIface {
119-
fn(owner, cloneSymbols(types))
99+
fn(owner, types)
120100
}
121101
}
122102

123103
// ForEachUseIfaceMethod visits each function's interface method demands.
124104
func (pm *PackageMeta) ForEachUseIfaceMethod(fn func(owner Symbol, demands []IfaceMethodDemand)) {
125-
if pm == nil {
126-
return
127-
}
128105
for owner, demands := range pm.useIfaceMethod {
129-
fn(owner, cloneIfaceMethodDemands(demands))
106+
fn(owner, demands)
130107
}
131108
}
132109

133110
// ForEachMethodInfo visits each concrete type's method slots.
134111
func (pm *PackageMeta) ForEachMethodInfo(fn func(typ Symbol, slots []MethodSlot)) {
135-
if pm == nil {
136-
return
137-
}
138112
for typ, slots := range pm.methodInfo {
139-
fn(typ, cloneMethodSlots(slots))
113+
fn(typ, slots)
140114
}
141115
}
142116

143117
// ForEachUseNamedMethod visits each function's constant MethodByName names.
144118
func (pm *PackageMeta) ForEachUseNamedMethod(fn func(owner Symbol, names []Name)) {
145-
if pm == nil {
146-
return
147-
}
148119
for owner, names := range pm.useNamedMethod {
149-
fn(owner, cloneNames(names))
120+
fn(owner, names)
150121
}
151122
}
152123

153124
// ForEachReflectMethod visits each function that needs conservative reflection handling.
154125
func (pm *PackageMeta) ForEachReflectMethod(fn func(owner Symbol)) {
155-
if pm == nil {
156-
return
157-
}
158126
for owner := range pm.reflectMethod {
159127
fn(owner)
160128
}
161129
}
162-
163-
func cloneSymbols(in []Symbol) []Symbol {
164-
return append([]Symbol(nil), in...)
165-
}
166-
167-
func cloneNames(in []Name) []Name {
168-
return append([]Name(nil), in...)
169-
}
170-
171-
func cloneMethodSigs(in []MethodSig) []MethodSig {
172-
return append([]MethodSig(nil), in...)
173-
}
174-
175-
func cloneIfaceMethodDemands(in []IfaceMethodDemand) []IfaceMethodDemand {
176-
return append([]IfaceMethodDemand(nil), in...)
177-
}
178-
179-
func cloneMethodSlots(in []MethodSlot) []MethodSlot {
180-
return append([]MethodSlot(nil), in...)
181-
}

internal/metadata/metadata_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ func TestBuilderSeparatesSymbolAndNameReferences(t *testing.T) {
4141
}
4242
}
4343

44+
func TestPackageMetaNameLookupsReturnEmptyStringForOutOfRangeIDs(t *testing.T) {
45+
pm := NewPackageMeta([]string{"main"})
46+
47+
if got := pm.SymbolName(Symbol(1)); got != "" {
48+
t.Fatalf("SymbolName(out-of-range) = %q, want empty string", got)
49+
}
50+
if got := pm.Name(Name(1)); got != "" {
51+
t.Fatalf("Name(out-of-range) = %q, want empty string", got)
52+
}
53+
}
54+
4455
func TestBuilderDeduplicatesFacts(t *testing.T) {
4556
b := NewBuilder()
4657
main := b.Symbol("main")
@@ -175,6 +186,26 @@ github.com/goplus/llgo/cl/_testmeta/interface_anonymous.use
175186
}
176187
}
177188

189+
func TestFormatMetaPrintsUnknownSymbolAndNameReferences(t *testing.T) {
190+
pm := NewPackageMeta([]string{"owner"})
191+
pm.useIface[Symbol(0)] = []Symbol{Symbol(2)}
192+
pm.useNamedMethod[Symbol(0)] = []Name{Name(3)}
193+
194+
got := MetaString(pm)
195+
want := `[UseIface]
196+
owner:
197+
?2
198+
199+
[UseNamedMethod]
200+
owner:
201+
?3
202+
203+
`
204+
if got != want {
205+
t.Fatalf("MetaString mismatch\ngot:\n%s\nwant:\n%s", got, want)
206+
}
207+
}
208+
178209
func assertSymbolGroup(t *testing.T, group string, pm *PackageMeta, visit func(func(Symbol, []Symbol)), key Symbol, want []Symbol) {
179210
t.Helper()
180211

0 commit comments

Comments
 (0)