Commit 26e0e8a8 authored by Matthew Dempsky's avatar Matthew Dempsky

cmd/compile: improve declaration position precision

Previously, n.Pos was reassigned to lineno when declare was called,
which might not match where the identifier actually appeared in the
source. This caused a loss of position precision for function
parameters (which were all declared at the last parameter's position),
and required some clumsy workarounds in bimport.go.

This CL changes declare to leave n.Pos alone and also fixes a few
places where n.Pos was not being set correctly.

Change-Id: Ibe5b5fd30609c684367207df701f9a1bfa82867f
Reviewed-on: https://go-review.googlesource.com/104275Reviewed-by: 's avatarRobert Griesemer <gri@golang.org>
parent c65a2781
...@@ -1454,7 +1454,7 @@ func (p *exporter) stmt(n *Node) { ...@@ -1454,7 +1454,7 @@ func (p *exporter) stmt(n *Node) {
switch op := n.Op; op { switch op := n.Op; op {
case ODCL: case ODCL:
p.op(ODCL) p.op(ODCL)
p.pos(n) p.pos(n.Left) // use declared variable's pos
p.sym(n.Left) p.sym(n.Left)
p.typ(n.Left.Type) p.typ(n.Left.Type)
......
...@@ -339,7 +339,7 @@ func (p *importer) obj(tag int) { ...@@ -339,7 +339,7 @@ func (p *importer) obj(tag int) {
sym := p.qualifiedName() sym := p.qualifiedName()
typ := p.typ() typ := p.typ()
val := p.value(typ) val := p.value(typ)
importconst(p.imp, sym, idealType(typ), npos(pos, nodlit(val))) importconst(pos, p.imp, sym, idealType(typ), val)
case aliasTag: case aliasTag:
pos := p.pos() pos := p.pos()
...@@ -376,11 +376,7 @@ func (p *importer) obj(tag int) { ...@@ -376,11 +376,7 @@ func (p *importer) obj(tag int) {
n := newfuncnamel(pos, sym) n := newfuncnamel(pos, sym)
n.Type = sig n.Type = sig
// TODO(mdempsky): Stop clobbering n.Pos in declare.
savedlineno := lineno
lineno = pos
declare(n, PFUNC) declare(n, PFUNC)
lineno = savedlineno
p.funcList = append(p.funcList, n) p.funcList = append(p.funcList, n)
importlist = append(importlist, n) importlist = append(importlist, n)
...@@ -501,11 +497,7 @@ func (p *importer) typ() *types.Type { ...@@ -501,11 +497,7 @@ func (p *importer) typ() *types.Type {
// read underlying type // read underlying type
t0 := p.typ() t0 := p.typ()
// TODO(mdempsky): Stop clobbering n.Pos in declare.
savedlineno := lineno
lineno = pos
p.importtype(t, t0) p.importtype(t, t0)
lineno = savedlineno
// interfaces don't have associated methods // interfaces don't have associated methods
if t0.IsInterface() { if t0.IsInterface() {
...@@ -781,6 +773,7 @@ func (p *importer) param(named bool) *types.Field { ...@@ -781,6 +773,7 @@ func (p *importer) param(named bool) *types.Field {
pkg = p.pkg() pkg = p.pkg()
} }
f.Sym = pkg.Lookup(name) f.Sym = pkg.Lookup(name)
// TODO(mdempsky): Need param position.
f.Nname = asTypesNode(newname(f.Sym)) f.Nname = asTypesNode(newname(f.Sym))
} }
...@@ -1109,7 +1102,7 @@ func (p *importer) node() *Node { ...@@ -1109,7 +1102,7 @@ func (p *importer) node() *Node {
p.bool() p.bool()
} }
pos := p.pos() pos := p.pos()
lhs := dclname(p.sym()) lhs := npos(pos, dclname(p.sym()))
typ := typenod(p.typ()) typ := typenod(p.typ())
return npos(pos, liststmt(variter([]*Node{lhs}, typ, nil))) // TODO(gri) avoid list creation return npos(pos, liststmt(variter([]*Node{lhs}, typ, nil))) // TODO(gri) avoid list creation
......
...@@ -16,7 +16,7 @@ func (p *noder) funcLit(expr *syntax.FuncLit) *Node { ...@@ -16,7 +16,7 @@ func (p *noder) funcLit(expr *syntax.FuncLit) *Node {
xfunc := p.nod(expr, ODCLFUNC, nil, nil) xfunc := p.nod(expr, ODCLFUNC, nil, nil)
xfunc.Func.SetIsHiddenClosure(Curfn != nil) xfunc.Func.SetIsHiddenClosure(Curfn != nil)
xfunc.Func.Nname = newfuncname(nblank.Sym) // filled in by typecheckclosure xfunc.Func.Nname = p.setlineno(expr, newfuncname(nblank.Sym)) // filled in by typecheckclosure
xfunc.Func.Nname.Name.Param.Ntype = xtype xfunc.Func.Nname.Name.Param.Ntype = xtype
xfunc.Func.Nname.Name.Defn = xfunc xfunc.Func.Nname.Name.Defn = xfunc
......
...@@ -26,33 +26,28 @@ func testdclstack() { ...@@ -26,33 +26,28 @@ func testdclstack() {
} }
} }
// redeclare emits a diagnostic about symbol s being redeclared somewhere. // redeclare emits a diagnostic about symbol s being redeclared at pos.
func redeclare(s *types.Sym, where string) { func redeclare(pos src.XPos, s *types.Sym, where string) {
if !s.Lastlineno.IsKnown() { if !s.Lastlineno.IsKnown() {
var tmp string pkg := s.Origpkg
if s.Origpkg != nil { if pkg == nil {
tmp = s.Origpkg.Path pkg = s.Pkg
} else {
tmp = s.Pkg.Path
} }
pkgstr := tmp yyerrorl(pos, "%v redeclared %s\n"+
yyerror("%v redeclared %s\n"+ "\tprevious declaration during import %q", s, where, pkg.Path)
"\tprevious declaration during import %q", s, where, pkgstr)
} else { } else {
line1 := lineno prevPos := s.Lastlineno
line2 := s.Lastlineno
// When an import and a declaration collide in separate files, // When an import and a declaration collide in separate files,
// present the import as the "redeclared", because the declaration // present the import as the "redeclared", because the declaration
// is visible where the import is, but not vice versa. // is visible where the import is, but not vice versa.
// See issue 4510. // See issue 4510.
if s.Def == nil { if s.Def == nil {
line2 = line1 pos, prevPos = prevPos, pos
line1 = s.Lastlineno
} }
yyerrorl(line1, "%v redeclared %s\n"+ yyerrorl(pos, "%v redeclared %s\n"+
"\tprevious declaration at %v", s, where, linestr(line2)) "\tprevious declaration at %v", s, where, linestr(prevPos))
} }
} }
...@@ -77,25 +72,26 @@ func declare(n *Node, ctxt Class) { ...@@ -77,25 +72,26 @@ func declare(n *Node, ctxt Class) {
// named OLITERAL needs Name; most OLITERALs don't. // named OLITERAL needs Name; most OLITERALs don't.
n.Name = new(Name) n.Name = new(Name)
} }
n.Pos = lineno
s := n.Sym s := n.Sym
// kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later. // kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
if !inimport && !typecheckok && s.Pkg != localpkg { if !inimport && !typecheckok && s.Pkg != localpkg {
yyerror("cannot declare name %v", s) yyerrorl(n.Pos, "cannot declare name %v", s)
} }
gen := 0 gen := 0
if ctxt == PEXTERN { if ctxt == PEXTERN {
if s.Name == "init" { if s.Name == "init" {
yyerror("cannot declare init - must be func") yyerrorl(n.Pos, "cannot declare init - must be func")
} }
if s.Name == "main" && localpkg.Name == "main" { if s.Name == "main" && localpkg.Name == "main" {
yyerror("cannot declare main - must be func") yyerrorl(n.Pos, "cannot declare main - must be func")
} }
externdcl = append(externdcl, n) externdcl = append(externdcl, n)
} else { } else {
if Curfn == nil && ctxt == PAUTO { if Curfn == nil && ctxt == PAUTO {
lineno = n.Pos
Fatalf("automatic outside function") Fatalf("automatic outside function")
} }
if Curfn != nil { if Curfn != nil {
...@@ -120,7 +116,7 @@ func declare(n *Node, ctxt Class) { ...@@ -120,7 +116,7 @@ func declare(n *Node, ctxt Class) {
// functype will print errors about duplicate function arguments. // functype will print errors about duplicate function arguments.
// Don't repeat the error here. // Don't repeat the error here.
if ctxt != PPARAM && ctxt != PPARAMOUT { if ctxt != PPARAM && ctxt != PPARAMOUT {
redeclare(s, "in this block") redeclare(n.Pos, s, "in this block")
} }
} }
......
...@@ -124,7 +124,7 @@ func dumpexport(bout *bio.Writer) { ...@@ -124,7 +124,7 @@ func dumpexport(bout *bio.Writer) {
func importsym(pkg *types.Pkg, s *types.Sym, op Op) { func importsym(pkg *types.Pkg, s *types.Sym, op Op) {
if asNode(s.Def) != nil && asNode(s.Def).Op != op { if asNode(s.Def) != nil && asNode(s.Def).Op != op {
pkgstr := fmt.Sprintf("during import %q", pkg.Path) pkgstr := fmt.Sprintf("during import %q", pkg.Path)
redeclare(s, pkgstr) redeclare(lineno, s, pkgstr)
} }
} }
...@@ -146,27 +146,16 @@ func pkgtype(pos src.XPos, pkg *types.Pkg, s *types.Sym) *types.Type { ...@@ -146,27 +146,16 @@ func pkgtype(pos src.XPos, pkg *types.Pkg, s *types.Sym) *types.Type {
return asNode(s.Def).Type return asNode(s.Def).Type
} }
// importconst declares symbol s as an imported constant with type t and value n. // importconst declares symbol s as an imported constant with type t and value val.
// pkg is the package being imported // pkg is the package being imported
func importconst(pkg *types.Pkg, s *types.Sym, t *types.Type, n *Node) { func importconst(pos src.XPos, pkg *types.Pkg, s *types.Sym, t *types.Type, val Val) {
importsym(pkg, s, OLITERAL) importsym(pkg, s, OLITERAL)
n = convlit(n, t)
if asNode(s.Def) != nil { // TODO: check if already the same. if asNode(s.Def) != nil { // TODO: check if already the same.
return return
} }
if n.Op != OLITERAL { n := npos(pos, nodlit(val))
yyerror("expression must be a constant") n = convlit1(n, t, false, reuseOK)
return
}
if n.Sym != nil {
n1 := *n
n = &n1
}
n.Orig = newname(s)
n.Sym = s n.Sym = s
declare(n, PEXTERN) declare(n, PEXTERN)
......
...@@ -313,8 +313,7 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) { ...@@ -313,8 +313,7 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
return return
} }
if my.Def != nil { if my.Def != nil {
lineno = pack.Pos redeclare(pack.Pos, my, "as imported package name")
redeclare(my, "as imported package name")
} }
my.Def = asTypesNode(pack) my.Def = asTypesNode(pack)
my.Lastlineno = pack.Pos my.Lastlineno = pack.Pos
...@@ -425,8 +424,7 @@ func (p *noder) declNames(names []*syntax.Name) []*Node { ...@@ -425,8 +424,7 @@ func (p *noder) declNames(names []*syntax.Name) []*Node {
} }
func (p *noder) declName(name *syntax.Name) *Node { func (p *noder) declName(name *syntax.Name) *Node {
// TODO(mdempsky): Set lineno? return p.setlineno(name, dclname(p.name(name)))
return dclname(p.name(name))
} }
func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node { func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
...@@ -452,7 +450,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node { ...@@ -452,7 +450,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
name = nblank.Sym // filled in by typecheckfunc name = nblank.Sym // filled in by typecheckfunc
} }
f.Func.Nname = newfuncname(name) f.Func.Nname = p.setlineno(fun.Name, newfuncname(name))
f.Func.Nname.Name.Defn = f f.Func.Nname.Name.Defn = f
f.Func.Nname.Name.Param.Ntype = t f.Func.Nname.Name.Param.Ntype = t
......
...@@ -268,7 +268,7 @@ func importdot(opkg *types.Pkg, pack *Node) { ...@@ -268,7 +268,7 @@ func importdot(opkg *types.Pkg, pack *Node) {
s1 := lookup(s.Name) s1 := lookup(s.Name)
if s1.Def != nil { if s1.Def != nil {
pkgerror := fmt.Sprintf("during import %q", opkg.Path) pkgerror := fmt.Sprintf("during import %q", opkg.Path)
redeclare(s1, pkgerror) redeclare(lineno, s1, pkgerror)
continue continue
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment