Skip to content

Commit

Permalink
interp: detect local redeclaration (#673)
Browse files Browse the repository at this point in the history
* interp: detect local redecleration

Fixes #666

* make make check happy

* fix typo in filenames, add them to the exclusion list

Co-authored-by: Marc Vertes <mvertes@free.fr>
  • Loading branch information
mpl and mvertes committed Jun 3, 2020
1 parent eb25c84 commit 6f87805
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 17 deletions.
15 changes: 15 additions & 0 deletions _test/redeclaration0.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

func main() {
type foo struct {
yolo string
}

var foo int
foo = 2
println(foo)
}

// Error:
// ../_test/redeclaration0.go:8:6: foo redeclared in this block
// previous declaration at ../_test/redeclaration0.go:4:7
12 changes: 12 additions & 0 deletions _test/redeclaration1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

func main() {
var foo string

var foo int
foo = 2
println(foo)
}

// Error:
// ../_test/redeclaration1.go:6:6: foo redeclared in this block
15 changes: 15 additions & 0 deletions _test/redeclaration2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

func main() {
var foo struct {
yolo string
}

var foo int
foo = 2
println(foo)
}

// Error:
// ../_test/redeclaration2.go:8:6: foo redeclared in this block
// previous declaration at ../_test/redeclaration2.go:4:6
13 changes: 13 additions & 0 deletions _test/redeclaration3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package main

func main() {
var foo int
foo = 2

type foo struct{}
var bar foo
println(bar)
}

// Error:
// ../_test/redeclaration3.go:7:7: foo redeclared in this block
14 changes: 14 additions & 0 deletions _test/redeclaration4.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

func main() {
var foo struct{
yolo string
}

type foo struct{}
var bar foo
println(bar)
}

// Error:
// ../_test/redeclaration4.go:8:7: foo redeclared in this block
14 changes: 14 additions & 0 deletions _test/redeclaration5.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

func main() {
type foo struct{
yolo string
}

type foo struct{}
var bar foo
println(bar)
}

// Error:
// ../_test/redeclaration5.go:8:7: foo redeclared in this block
55 changes: 38 additions & 17 deletions interp/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,24 +355,32 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {

case typeSpec:
// processing already done in GTA pass for global types, only parses inlined types
if sc.def != nil {
typeName := n.child[0].ident
var typ *itype
if typ, err = nodeType(interp, sc, n.child[1]); err != nil {
return false
}
if typ.incomplete {
err = n.cfgErrorf("invalid type declaration")
return false
}
if n.child[1].kind == identExpr {
n.typ = &itype{cat: aliasT, val: typ, name: typeName}
} else {
n.typ = typ
n.typ.name = typeName
}
sc.sym[typeName] = &symbol{kind: typeSym, typ: n.typ}
if sc.def == nil {
return false
}
typeName := n.child[0].ident
var typ *itype
if typ, err = nodeType(interp, sc, n.child[1]); err != nil {
return false
}
if typ.incomplete {
err = n.cfgErrorf("invalid type declaration")
return false
}

if _, exists := sc.sym[typeName]; exists {
// TODO(mpl): find the exact location of the previous declaration
err = n.cfgErrorf("%s redeclared in this block", typeName)
return false
}

if n.child[1].kind == identExpr {
n.typ = &itype{cat: aliasT, val: typ, name: typeName}
} else {
n.typ = typ
n.typ.name = typeName
}
sc.sym[typeName] = &symbol{kind: typeSym, typ: n.typ}
return false

case constDecl:
Expand Down Expand Up @@ -1676,6 +1684,19 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
// Global object allocation is already performed in GTA.
index = sc.sym[c.ident].index
} else {
if sym, exists := sc.sym[c.ident]; exists {
if sym.typ.node != nil &&
sym.typ.node.anc != nil {
// for non-predeclared identifiers (struct, map, etc)
prevDecl := n.interp.fset.Position(sym.typ.node.anc.pos)
err = n.cfgErrorf("%s redeclared in this block\n\tprevious declaration at %v", c.ident, prevDecl)
return
}
// for predeclared identifiers (int, string, etc)
// TODO(mpl): find the exact location of the previous declaration in all cases.
err = n.cfgErrorf("%s redeclared in this block", c.ident)
return
}
index = sc.add(n.typ)
sc.sym[c.ident] = &symbol{index: index, kind: varSym, typ: n.typ}
}
Expand Down
6 changes: 6 additions & 0 deletions interp/interp_consistent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ func TestInterpConsistencyBuild(t *testing.T) {
file.Name() == "type5.go" || // used to illustrate a limitation with no workaround, related to the fact that the reflect package does not allow the creation of named types
file.Name() == "type6.go" || // used to illustrate a limitation with no workaround, related to the fact that the reflect package does not allow the creation of named types

file.Name() == "redeclaration0.go" || // expect error
file.Name() == "redeclaration1.go" || // expect error
file.Name() == "redeclaration2.go" || // expect error
file.Name() == "redeclaration3.go" || // expect error
file.Name() == "redeclaration4.go" || // expect error
file.Name() == "redeclaration5.go" || // expect error
file.Name() == "server6.go" || // syntax parsing
file.Name() == "server5.go" || // syntax parsing
file.Name() == "server4.go" || // syntax parsing
Expand Down

0 comments on commit 6f87805

Please sign in to comment.