interp: enable declaration errors detection at parsing time
The Go parser is able to detect some (but not all) (re-)decleration errors, if the DeclarationErrors flag is enabled, which was not done so far. This PR therefore enables that flag, which allows the removal of some of the now unneeded code that was recently added to support redeclarations. Fixes #811
This commit is contained in:
@@ -12,4 +12,5 @@ func main() {
|
||||
}
|
||||
|
||||
// Error:
|
||||
// ../_test/redeclaration-global5.go:5:1: time redeclared in this block
|
||||
// ../_test/redeclaration-global5.go:5:6: time redeclared in this block
|
||||
// previous declaration at ../_test/redeclaration-global5.go:3:5
|
||||
|
||||
@@ -365,7 +365,7 @@ func wrapInMain(src string) string {
|
||||
// interpreter's FileSet.
|
||||
func (interp *Interpreter) ast(src, name string, inc bool) (string, *node, error) {
|
||||
var inFunc bool
|
||||
var mode parser.Mode
|
||||
mode := parser.DeclarationErrors
|
||||
|
||||
// Allow incremental parsing of declarations or statements, by inserting
|
||||
// them in a pseudo file package or function. Those statements or
|
||||
|
||||
@@ -386,12 +386,6 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
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 {
|
||||
@@ -1781,18 +1775,6 @@ func (interp *Interpreter) cfg(root *node, importPath 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)
|
||||
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}
|
||||
}
|
||||
|
||||
@@ -110,21 +110,12 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
|
||||
}
|
||||
for _, c := range n.child[:l] {
|
||||
asImportName := filepath.Join(c.ident, baseName)
|
||||
sym1, exists1 := sc.sym[asImportName]
|
||||
sym2, exists2 := sc.sym[c.ident]
|
||||
if !exists1 && !exists2 {
|
||||
sym, exists := sc.sym[asImportName]
|
||||
if !exists {
|
||||
sc.sym[c.ident] = &symbol{index: sc.add(n.typ), kind: varSym, global: true, typ: n.typ, node: n}
|
||||
continue
|
||||
}
|
||||
|
||||
var sym *symbol
|
||||
if exists1 {
|
||||
// prev declaration is an import statement
|
||||
sym = sym1
|
||||
} else {
|
||||
// prev declaration is whatever else (var, type, etc)
|
||||
sym = sym2
|
||||
}
|
||||
// redeclaration error
|
||||
if sym.typ.node != nil && sym.typ.node.anc != nil {
|
||||
prevDecl := n.interp.fset.Position(sym.typ.node.anc.pos)
|
||||
@@ -142,7 +133,6 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
|
||||
ident := n.child[1].ident
|
||||
switch {
|
||||
case isMethod(n):
|
||||
// TODO(mpl): redeclaration detection
|
||||
// Add a method symbol in the receiver type name space
|
||||
var rcvrtype *itype
|
||||
n.ident = ident
|
||||
@@ -179,19 +169,6 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
|
||||
err = n.cfgErrorf("%s redeclared in this block", ident)
|
||||
return false
|
||||
}
|
||||
sym, exists := sc.sym[ident]
|
||||
if exists {
|
||||
// Make sure the symbol we found seems to be about another node, before calling
|
||||
// it a redeclaration.
|
||||
if sym.typ.isComplete() {
|
||||
// TODO(mpl): this check might be too permissive?
|
||||
if sym.kind != funcSym || sym.typ.cat != n.typ.cat || sym.node != n || sym.index != -1 {
|
||||
// redeclaration error
|
||||
err = n.cfgErrorf("%s redeclared in this block", ident)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add a function symbol in the package name space except for init
|
||||
sc.sym[n.child[1].ident] = &symbol{kind: funcSym, typ: n.typ, node: n, index: -1}
|
||||
}
|
||||
@@ -235,7 +212,7 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
|
||||
break
|
||||
}
|
||||
|
||||
// redeclaration error
|
||||
// redeclaration error. Not caught by the parser.
|
||||
err = n.cfgErrorf("%s redeclared in this block", name)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -821,7 +821,7 @@ func TestMultiEvalNoName(t *testing.T) {
|
||||
_, err = i.Eval(string(data))
|
||||
if k == 1 {
|
||||
expectedErr := fmt.Errorf("3:8: fmt/%s redeclared in this block", interp.DefaultSourceName)
|
||||
if err.Error() != expectedErr.Error() {
|
||||
if err == nil || err.Error() != expectedErr.Error() {
|
||||
t.Fatalf("unexpected result; wanted error %v, got %v", expectedErr, err)
|
||||
}
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user