Skip to content

Commit 321fa3d

Browse files
Fixing full name uniqueness
1 parent 743b099 commit 321fa3d

File tree

5 files changed

+119
-46
lines changed

5 files changed

+119
-46
lines changed

compiler/compiler_test.go

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,8 @@ func TestDeclSelection_RemoveUnusedNestedTypesInFunction(t *testing.T) {
387387
sel.IsDead(`func:command-line-arguments.Foo<int>`)
388388

389389
sel.IsAlive(`typeVar:command-line-arguments.Bar`)
390-
sel.IsAlive(`type:command-line-arguments.Bar<string;>`)
391-
sel.IsDead(`type:command-line-arguments.Bar<int;>`)
390+
sel.IsAlive(`type:command-line-arguments.Bar<string;>@main.go:4:9`)
391+
sel.IsDead(`type:command-line-arguments.Bar<int;>@main.go:4:9`)
392392

393393
sel.IsDead(`funcVar:command-line-arguments.deadCode`)
394394
sel.IsDead(`func:command-line-arguments.deadCode`)
@@ -423,8 +423,8 @@ func TestDeclSelection_RemoveUnusedNestedTypesInMethod(t *testing.T) {
423423
sel.IsAlive(`func:command-line-arguments.(*Baz).Foo<string>`)
424424

425425
sel.IsAlive(`typeVar:command-line-arguments.Bar`)
426-
sel.IsDead(`type:command-line-arguments.Bar<int;>`)
427-
sel.IsAlive(`type:command-line-arguments.Bar<string;>`)
426+
sel.IsDead(`type:command-line-arguments.Bar<int;>@main.go:5:9`)
427+
sel.IsAlive(`type:command-line-arguments.Bar<string;>@main.go:5:9`)
428428

429429
sel.IsDead(`funcVar:command-line-arguments.deadCode`)
430430
sel.IsDead(`func:command-line-arguments.deadCode`)
@@ -445,15 +445,16 @@ func TestDeclSelection_RemoveAllUnusedNestedTypes(t *testing.T) {
445445

446446
srcFiles := []srctesting.Source{{Name: `main.go`, Contents: []byte(src)}}
447447
sel := declSelection(t, srcFiles, nil)
448+
sel.PrintDeclStatus()
448449
sel.IsAlive(`func:command-line-arguments.main`)
449450

450451
sel.IsDead(`funcVar:command-line-arguments.Foo`)
451452
sel.IsDead(`func:command-line-arguments.Foo<string>`)
452453
sel.IsDead(`func:command-line-arguments.Foo<int>`)
453454

454455
sel.IsDead(`typeVar:command-line-arguments.Bar`)
455-
sel.IsDead(`type:command-line-arguments.Bar<string;>`)
456-
sel.IsDead(`type:command-line-arguments.Bar<int;>`)
456+
sel.IsDead(`type:command-line-arguments.Bar<string;>@main.go:4:9`)
457+
sel.IsDead(`type:command-line-arguments.Bar<int;>@main.go:4:9`)
457458

458459
sel.IsDead(`funcVar:command-line-arguments.deadCode`)
459460
sel.IsDead(`func:command-line-arguments.deadCode`)
@@ -473,14 +474,15 @@ func TestDeclSelection_CompletelyRemoveNestedType(t *testing.T) {
473474

474475
srcFiles := []srctesting.Source{{Name: `main.go`, Contents: []byte(src)}}
475476
sel := declSelection(t, srcFiles, nil)
477+
sel.PrintDeclStatus()
476478

477479
sel.IsAlive(`func:command-line-arguments.main`)
478480

479481
sel.IsDead(`funcVar:command-line-arguments.Foo`)
480482
sel.IsDead(`func:command-line-arguments.Foo<int>`)
481483

482484
sel.IsDead(`typeVar:command-line-arguments.Bar`)
483-
sel.IsDead(`type:command-line-arguments.Bar<int;>`)
485+
sel.IsDead(`type:command-line-arguments.Bar<int;>@main.go:4:9`)
484486

485487
sel.IsDead(`funcVar:command-line-arguments.deadCode`)
486488
sel.IsDead(`func:command-line-arguments.deadCode`)
@@ -719,30 +721,30 @@ func TestDeclNaming_InitsAndVars(t *testing.T) {
719721
checkForDeclFullNames(t, archives,
720722
// tully
721723
`var:github.com/gopherjs/gopherjs/compiler/tully.keymaster`,
722-
`funcVar:github.com/gopherjs/gopherjs/compiler/tully.init`,
723-
`funcVar:github.com/gopherjs/gopherjs/compiler/tully.init`,
724-
`func:github.com/gopherjs/gopherjs/compiler/tully.init`,
725-
`func:github.com/gopherjs/gopherjs/compiler/tully.init`,
724+
`funcVar:github.com/gopherjs/gopherjs/compiler/tully.init@b.go:3:8`,
725+
`funcVar:github.com/gopherjs/gopherjs/compiler/tully.init@a.go:2:8`,
726+
`func:github.com/gopherjs/gopherjs/compiler/tully.init@b.go:3:8`,
727+
`func:github.com/gopherjs/gopherjs/compiler/tully.init@a.go:2:8`,
726728

727729
// spangler
728730
`var:github.com/gopherjs/gopherjs/compiler/spengler.egie`,
729-
`funcVar:github.com/gopherjs/gopherjs/compiler/spengler.init`,
730-
`funcVar:github.com/gopherjs/gopherjs/compiler/spengler.init`,
731-
`func:github.com/gopherjs/gopherjs/compiler/spengler.init`,
732-
`func:github.com/gopherjs/gopherjs/compiler/spengler.init`,
731+
`funcVar:github.com/gopherjs/gopherjs/compiler/spengler.init@a.go:2:8`,
732+
`funcVar:github.com/gopherjs/gopherjs/compiler/spengler.init@a.go:4:8`,
733+
`func:github.com/gopherjs/gopherjs/compiler/spengler.init@a.go:2:8`,
734+
`func:github.com/gopherjs/gopherjs/compiler/spengler.init@a.go:4:8`,
733735

734736
// barrett
735-
`funcVar:github.com/gopherjs/gopherjs/compiler/barrett.init`,
736-
`funcVar:github.com/gopherjs/gopherjs/compiler/barrett.init`,
737-
`funcVar:github.com/gopherjs/gopherjs/compiler/barrett.init`,
738-
`func:github.com/gopherjs/gopherjs/compiler/barrett.init`,
739-
`func:github.com/gopherjs/gopherjs/compiler/barrett.init`,
740-
`func:github.com/gopherjs/gopherjs/compiler/barrett.init`,
737+
`funcVar:github.com/gopherjs/gopherjs/compiler/barrett.init@c.go:2:8`,
738+
`funcVar:github.com/gopherjs/gopherjs/compiler/barrett.init@b.go:2:8`,
739+
`funcVar:github.com/gopherjs/gopherjs/compiler/barrett.init@a.go:2:8`,
740+
`func:github.com/gopherjs/gopherjs/compiler/barrett.init@c.go:2:8`,
741+
`func:github.com/gopherjs/gopherjs/compiler/barrett.init@b.go:2:8`,
742+
`func:github.com/gopherjs/gopherjs/compiler/barrett.init@a.go:2:8`,
741743

742744
// main
743745
`var:command-line-arguments.peck`,
744-
`funcVar:command-line-arguments.init`,
745-
`func:command-line-arguments.init`,
746+
`funcVar:command-line-arguments.init@main.go:11:8`,
747+
`func:command-line-arguments.init@main.go:11:8`,
746748
`funcVar:command-line-arguments.main`,
747749
`func:command-line-arguments.main`,
748750
`init:main`,
@@ -774,7 +776,7 @@ func TestDeclNaming_VarsAndTypes(t *testing.T) {
774776
archives := compileProject(t, root, false)
775777
checkForDeclFullNames(t, archives,
776778
`var:command-line-arguments.shawn`,
777-
`var:blank`,
779+
`var:blank@main.go:8:7`,
778780

779781
`var:command-line-arguments.fezzik`,
780782
`anonType:command-line-arguments.structType`,

compiler/declCache.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,43 @@
11
package compiler
22

3+
import (
4+
"encoding/gob"
5+
"fmt"
6+
)
7+
38
type DeclCache struct {
49
enabled bool
5-
// TODO: Implement decl cache.
10+
decls map[string]*Decl
11+
}
12+
13+
func init() {
14+
gob.Register(&DeclCache{})
615
}
716

817
func NewDeclCache(enable bool) *DeclCache {
918
return &DeclCache{
1019
enabled: enable,
20+
decls: map[string]*Decl{},
1121
}
1222
}
1323

14-
// TODO: May need a more unique key since some decls may not have unique names.
1524
func (dc *DeclCache) GetDecl(fullname string) *Decl {
16-
return nil
25+
return dc.decls[fullname]
1726
}
1827

1928
func (dc *DeclCache) PutDecl(decl *Decl) {
29+
if !dc.enabled {
30+
// If not enabled, do nothing since the cache is not being stored.
31+
return
32+
}
2033

34+
if existing, ok := dc.decls[decl.FullName]; ok {
35+
if existing != decl {
36+
panic(fmt.Errorf(`decl cache conflict: different decls with same name: %q`, decl.FullName))
37+
}
38+
return
39+
}
40+
dc.decls[decl.FullName] = decl
2141
}
2242

2343
func (dc *DeclCache) Read(decode func(any) error) error {

compiler/declNames.go

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package compiler
22

33
import (
4+
"fmt"
5+
"go/token"
46
"go/types"
7+
"path"
58

69
"github.com/gopherjs/gopherjs/compiler/internal/symbol"
710
"github.com/gopherjs/gopherjs/compiler/internal/typeparams"
@@ -16,23 +19,41 @@ func importDeclFullName(importedPkg *types.Package) string {
1619

1720
// varDeclFullName returns a name for a package-level variable declaration.
1821
// This var name only references the first named variable in an assignment.
19-
// If no variables are named, the name is `var:blank` and not unique.
20-
func varDeclFullName(init *types.Initializer) string {
22+
//
23+
// If no variables are named, this will attempt to create a unique name
24+
// using the integer value of the first valid position of the blank variables.
25+
// Otherwise the name is `var:blank` and is not unique.
26+
func varDeclFullName(init *types.Initializer, fSet *token.FileSet) string {
2127
for _, lhs := range init.Lhs {
2228
if lhs.Name() != `_` {
2329
return `var:` + symbol.New(lhs).String()
2430
}
2531
}
32+
33+
for _, lhs := range init.Lhs {
34+
if pos := lhs.Pos(); pos.IsValid() {
35+
return `var:blank` + declFullNameDiscriminator(pos, fSet)
36+
}
37+
}
38+
2639
return `var:blank`
2740
}
2841

2942
// funcVarDeclFullName returns a name for a package-level variable
3043
// that is used for a function (without a receiver) declaration.
31-
// The name is unique unless the function is an `init` function.
32-
// If the function is generic, this declaration name is also for the list
44+
// If the function is generic, this declaration name is for the list
3345
// of instantiations of the function.
34-
func funcVarDeclFullName(o *types.Func) string {
35-
return `funcVar:` + symbol.New(o).String()
46+
//
47+
// The name is unique unless the function is an `init` function.
48+
// If the name is for an `init` function, the position of the function
49+
// is used to create a unique name if it is valid,
50+
// otherwise the name is not unique.
51+
func funcVarDeclFullName(o *types.Func, fSet *token.FileSet) string {
52+
name := `funcVar:` + symbol.New(o).String()
53+
if o.Name() == `init` {
54+
name += declFullNameDiscriminator(o.Pos(), fSet)
55+
}
56+
return name
3657
}
3758

3859
// mainFuncDeclFullName returns the name for the declaration used to invoke the
@@ -43,9 +64,14 @@ func mainFuncDeclFullName() string {
4364

4465
// funcDeclFullName returns a name for a package-level function
4566
// declaration for the given instance of a function.
46-
// The name is unique unless the function is an `init` function.
47-
func funcDeclFullName(inst typeparams.Instance) string {
48-
return `func:` + inst.String()
67+
// The name is unique unless the function is an `init` function
68+
// then it tries to use the position of the function to create a unique name.
69+
func funcDeclFullName(inst typeparams.Instance, fSet *token.FileSet) string {
70+
name := `func:` + inst.String()
71+
if inst.IsTrivial() && inst.Object.Name() == `init` {
72+
name += declFullNameDiscriminator(inst.Object.Pos(), fSet)
73+
}
74+
return name
4975
}
5076

5177
// typeVarDeclFullName returns a unique name for a package-level variable
@@ -57,11 +83,16 @@ func typeVarDeclFullName(o *types.TypeName) string {
5783
}
5884

5985
// typeDeclFullName returns a unique name for a package-level type declaration
60-
// for the given instance of a type. Names are only unique per scope package
86+
// for the given instance of a type. Names are only unique per package
6187
// unless the type is a nested type then the name is only unique per the
62-
// function or method it is declared in.
63-
func typeDeclFullName(inst typeparams.Instance) string {
64-
return `type:` + inst.String()
88+
// function or method it is declared in. In that case, the position of the
89+
// declaration is used to try to create a unique name.
90+
func typeDeclFullName(inst typeparams.Instance, fSet *token.FileSet) string {
91+
name := `type:` + inst.String()
92+
if typeparams.FindNestingFunc(inst.Object) != nil {
93+
name += declFullNameDiscriminator(inst.Object.Pos(), fSet)
94+
}
95+
return name
6596
}
6697

6798
// anonTypeDeclFullName returns a unique name for a package-level type
@@ -70,3 +101,16 @@ func typeDeclFullName(inst typeparams.Instance) string {
70101
func anonTypeDeclFullName(o types.Object) string {
71102
return `anonType:` + symbol.New(o).String()
72103
}
104+
105+
// declFullNameDiscriminator returns a string representing the position of a
106+
// declaration that is used to differentiate declarations with the same name.
107+
// Since the package path will already be part of the full name, only the file,
108+
// line, and column are used.
109+
// If position is invalid, an empty string is returned.
110+
func declFullNameDiscriminator(pos token.Pos, fSet *token.FileSet) string {
111+
if !pos.IsValid() {
112+
return ``
113+
}
114+
p := fSet.Position(pos)
115+
return fmt.Sprintf("@%s:%d:%d", path.Base(p.Filename), p.Line, p.Column)
116+
}

compiler/decls.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -266,12 +266,14 @@ func (fc *funcContext) varDecls(vars []*types.Var) []*Decl {
266266
// newVarDecl creates a new Decl describing a variable, given an explicit
267267
// initializer.
268268
func (fc *funcContext) newVarDecl(init *types.Initializer) *Decl {
269-
fullName := varDeclFullName(init)
269+
fullName := varDeclFullName(init, fc.pkgCtx.fileSet)
270270
if d := fc.getCachedDecl(fullName); d != nil {
271271
return d
272272
}
273273

274-
d := &Decl{FullName: fullName}
274+
d := &Decl{
275+
FullName: fullName,
276+
}
275277
assignLHS := []ast.Expr{}
276278
for _, o := range init.Lhs {
277279
assignLHS = append(assignLHS, fc.newIdentFor(o))
@@ -356,7 +358,7 @@ func (fc *funcContext) funcDecls(functions []*ast.FuncDecl) ([]*Decl, error) {
356358
}
357359

358360
func (fc *funcContext) newFuncVarDecl(fun *ast.FuncDecl, o *types.Func, instances []typeparams.Instance) *Decl {
359-
fullName := funcVarDeclFullName(o)
361+
fullName := funcVarDeclFullName(o, fc.pkgCtx.fileSet)
360362
if varDecl := fc.getCachedDecl(fullName); varDecl != nil {
361363
return varDecl
362364
}
@@ -402,7 +404,7 @@ func (fc *funcContext) newCallMainFuncDecl(mainFunc *types.Func) *Decl {
402404

403405
// newFuncDecl returns a Decl that defines a package-level function or a method.
404406
func (fc *funcContext) newFuncDecl(fun *ast.FuncDecl, inst typeparams.Instance) *Decl {
405-
fullName := funcDeclFullName(inst)
407+
fullName := funcDeclFullName(inst, fc.pkgCtx.fileSet)
406408
if d := fc.getCachedDecl(fullName); d != nil {
407409
return d
408410
}
@@ -543,7 +545,7 @@ func (fc *funcContext) newNamedTypeVarDecl(obj *types.TypeName) *Decl {
543545
// newNamedTypeInstDecl returns a Decl that represents an instantiation of a
544546
// named Go type.
545547
func (fc *funcContext) newNamedTypeInstDecl(inst typeparams.Instance) (*Decl, error) {
546-
fullName := typeDeclFullName(inst)
548+
fullName := typeDeclFullName(inst, fc.pkgCtx.fileSet)
547549
if d := fc.getCachedDecl(fullName); d != nil {
548550
return d, nil
549551
}

compiler/package.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ type funcContext struct {
119119
}
120120

121121
func newRootCtx(tContext *types.Context, srcs *sources.Sources, minify bool) *funcContext {
122+
declCache, ok := srcs.CacheData.(*DeclCache)
123+
if !ok {
124+
declCache = NewDeclCache(false)
125+
}
126+
122127
funcCtx := &funcContext{
123128
FuncInfo: srcs.TypeInfo.InitFuncInfo,
124129
pkgCtx: &pkgContext{
@@ -133,7 +138,7 @@ func newRootCtx(tContext *types.Context, srcs *sources.Sources, minify bool) *fu
133138
minify: minify,
134139
fileSet: srcs.FileSet,
135140
instanceSet: srcs.TypeInfo.InstanceSets,
136-
declCache: srcs.CacheData.(*DeclCache),
141+
declCache: declCache,
137142
},
138143
allVars: make(map[string]int),
139144
flowDatas: map[*types.Label]*flowData{nil: {}},

0 commit comments

Comments
 (0)