Skip to content

Commit

Permalink
allowing const decl in generic pkg
Browse files Browse the repository at this point in the history
  • Loading branch information
dlepex committed Mar 23, 2018
1 parent 09f1aee commit f70f3bf
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 15 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ __Generic packages cannot contain non-generic code__, move it to separate non-ge
Non-generic code includes:
- functions (w/o receiver), excluding constructors of generic types
- non-generic types and their methods
- var and const declarations
- var declarations

Const declarations are allowed in generic packages. Typeinst directly substitutes constants by their values.

Generic package may import other packages. However, imported packages are never treated as generic themselves.

Expand Down
6 changes: 6 additions & 0 deletions print.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ func (td *TypeDesc) printedName(n string) string {
}

func (pk *PkgDesc) renameFunc(args *TypeArgs, inCtor bool) pri.RenameFunc {

stringer := astStringer{}
return func(id *ast.Ident) string {
n := id.Name
if pk.occTypes.Has(id) {
Expand All @@ -79,6 +81,10 @@ func (pk *PkgDesc) renameFunc(args *TypeArgs, inCtor bool) pri.RenameFunc {
return n
}
}
if pk.occConsts.Has(id) {
v := pk.consts[n]
return stringer.ToString(v)
}
if inCtor {
if pk.occCtors.Has(id) {
t := pk.ctors[n]
Expand Down
14 changes: 12 additions & 2 deletions testdata/g/maps/maps.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
// nolint
package maps

import (
"fmt"
)

type K = interface{}
type V = interface{}

Expand All @@ -16,6 +21,9 @@ func (m Map) KeyValues(keys *[]K, values *[]V) {
}
}

const helloWorld uint32 = 20
const helloWorld1 string = "a"

type TreeMap struct {
l *Node
r *Node
Expand All @@ -31,13 +39,15 @@ func create(keys []K, values []V) *TreeMap {
}

func (t *TreeMap) Put(k K, v V) {

fmt.Printf("%v %s", helloWorld, helloWorld1)
}

const maxW = 99

func makeWrappers() []*wrapper {
return nil
}

func makeWrappers99() []**[99]*[]wrapper {
func makeWrappers99() []**[maxW]*[]wrapper {
return nil
}
12 changes: 11 additions & 1 deletion testdata/g/maps/nd.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
// nolint
package maps

import (
"fmt"
)

type Node struct {
key K
val V
Expand All @@ -22,5 +26,11 @@ func (_ Maps) Create(keys []K, mapper func(K) V) map[K]V {
type Maps2 struct{}

func (_ Maps2) Create2(keys []K, mapper func(K) V) map[K]V {
return nil
x := maxW
fmt.Print(x)
switch len(keys) {
case maxW:
return nil
}
return make(map[K]V)
}
55 changes: 44 additions & 11 deletions walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ type (
funcs map[string]*ast.FuncDecl // free standing funcs (i.e. no recever), excluding type ctors
impRename map[string]string // what packages should be renamed within pkg AST: name -> newname
strict bool // strict mode means all typevars of the pkg are markerd with special comment "//typeinst: typevar"
consts map[string]ast.Expr // const -> value
occTypes AstIdentSet // occurences of types identifiers in AST (that may be renamed)
occPkgs AstIdentSet // occurences of packages identifiers in AST (that must be renamed)
occCtors AstIdentSet // occurences of constructor functions ...
occPkgs AstIdentSet // ... of packages identifiers ...
occCtors AstIdentSet // ... of constructor functions ...
occConsts AstIdentSet // ... of constants ...
}

// TypeDesc provides full type info
Expand Down Expand Up @@ -137,6 +139,7 @@ func (impl *Impl) Package(pkgPath string, imports Imports) (pkg *PkgDesc, err er
funcs := make(map[string]*ast.FuncDecl)
tpvars := NewStrSet()
fset := token.NewFileSet()
consts := make(map[string]ast.Expr)
pkgpath := packagePath(unquote(pkgPath))
if pkgpath == "" {
return nil, fmt.Errorf("no such package: %s", pkgPath)
Expand All @@ -162,7 +165,8 @@ func (impl *Impl) Package(pkgPath string, imports Imports) (pkg *PkgDesc, err er
funcs[decl.Name.Name] = decl
}
case *ast.GenDecl:
if decl.Tok == token.TYPE {
switch decl.Tok {
case token.TYPE:
for _, spec := range decl.Specs {
tsp := spec.(*ast.TypeSpec)
name := tsp.Name.Name
Expand All @@ -179,6 +183,27 @@ func (impl *Impl) Package(pkgPath string, imports Imports) (pkg *PkgDesc, err er
}
}
}
case token.CONST:
for _, spec := range decl.Specs {
spec := spec.(*ast.ValueSpec)
t := spec.Type
if t != nil {
if i := t.(*ast.Ident); i.Name == "string" {
t = nil
}
}
for i, id := range spec.Names {
val := spec.Values[i]
if t != nil {
// typed constant case: type(const)
val = &ast.CallExpr{
Fun: t,
Args: []ast.Expr{val},
}
}
consts[id.Name] = val
}
}
}
}
}
Expand All @@ -191,8 +216,8 @@ func (impl *Impl) Package(pkgPath string, imports Imports) (pkg *PkgDesc, err er
impRename = impl.imports.Merge(imports)
}

pkg = &PkgDesc{pkgPath, types, make(map[string]*TypeDesc), tpvars, NewStrSet(), funcs, impRename, len(tpvars) > 0,
NewAstIdentSet(), NewAstIdentSet(), NewAstIdentSet()}
pkg = &PkgDesc{pkgPath, types, make(map[string]*TypeDesc), tpvars, NewStrSet(), funcs, impRename, len(tpvars) > 0, consts,
NewAstIdentSet(), NewAstIdentSet(), NewAstIdentSet(), NewAstIdentSet()}
pkg.detectCtors()
impl.pkg[pkgPath] = pkg
return
Expand Down Expand Up @@ -416,15 +441,23 @@ func (pd *PkgDesc) markOccurences(p astWalkerParams) {
if p.kind == ast.Typ || p.kind == ast.Bad {
if pd.generic.Has(n) || pd.typevars.Has(n) {
pd.occTypes.Add(p.id)
return
}
} else if p.kind == ast.Fun || p.kind == ast.Bad {
}
if p.kind == ast.Con || p.kind == ast.Bad {
if _, has := pd.consts[n]; has {
pd.occConsts.Add(p.id)
return
}
}
if p.kind == ast.Fun || p.kind == ast.Bad {
if _, has := pd.ctors[n]; has {
pd.occCtors.Add(p.id)
return
}
} else {
if _, has := pd.impRename[n]; has {
pd.occPkgs.Add(p.id)
}
}
if _, has := pd.impRename[n]; has {
pd.occPkgs.Add(p.id)
}
}

Expand Down Expand Up @@ -474,7 +507,7 @@ func (w astWalker) Visit(node ast.Node) ast.Visitor {
w(astWalkerParams{node, ast.Bad})
} else {
switch node.Obj.Kind {
case ast.Typ, ast.Fun:
case ast.Typ, ast.Fun, ast.Con:
w(astWalkerParams{node, node.Obj.Kind})
}
}
Expand Down

0 comments on commit f70f3bf

Please sign in to comment.