Commit 3f132a82 authored by Robert Griesemer's avatar Robert Griesemer

go/types: more robust imports

- imported objects don't have position information
- gc exported data contains non-exported objects at
  the top-level, guard against them
- better error message when dot-imports conflict
  with local declarations

R=adonovan, r
CC=golang-dev
https://golang.org/cl/7379052
parent 1caaff6b
...@@ -900,8 +900,11 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle ...@@ -900,8 +900,11 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
if ident, ok := e.X.(*ast.Ident); ok { if ident, ok := e.X.(*ast.Ident); ok {
if pkg, ok := check.lookup(ident).(*Package); ok { if pkg, ok := check.lookup(ident).(*Package); ok {
exp := pkg.Scope.Lookup(sel) exp := pkg.Scope.Lookup(sel)
if exp == nil { // gcimported package scopes contain non-exported
check.errorf(e.Sel.Pos(), "cannot refer to unexported %s", sel) // objects such as types used in partially exported
// objects - do not accept them
if exp == nil || !ast.IsExported(exp.GetName()) {
check.errorf(e.Pos(), "cannot refer to unexported %s", e)
goto Error goto Error
} }
check.register(e.Sel, exp) check.register(e.Sel, exp)
......
...@@ -89,7 +89,13 @@ func (obj *TypeName) GetType() Type { return obj.Type } ...@@ -89,7 +89,13 @@ func (obj *TypeName) GetType() Type { return obj.Type }
func (obj *Var) GetType() Type { return obj.Type } func (obj *Var) GetType() Type { return obj.Type }
func (obj *Func) GetType() Type { return obj.Type } func (obj *Func) GetType() Type { return obj.Type }
func (obj *Package) GetPos() token.Pos { return obj.spec.Pos() } func (obj *Package) GetPos() token.Pos {
if obj.spec != nil {
return obj.spec.Pos()
}
return token.NoPos
}
func (obj *Const) GetPos() token.Pos { func (obj *Const) GetPos() token.Pos {
for _, n := range obj.spec.Names { for _, n := range obj.spec.Names {
if n.Name == obj.Name { if n.Name == obj.Name {
...@@ -98,7 +104,13 @@ func (obj *Const) GetPos() token.Pos { ...@@ -98,7 +104,13 @@ func (obj *Const) GetPos() token.Pos {
} }
return token.NoPos return token.NoPos
} }
func (obj *TypeName) GetPos() token.Pos { return obj.spec.Pos() } func (obj *TypeName) GetPos() token.Pos {
if obj.spec != nil {
return obj.spec.Pos()
}
return token.NoPos
}
func (obj *Var) GetPos() token.Pos { func (obj *Var) GetPos() token.Pos {
switch d := obj.decl.(type) { switch d := obj.decl.(type) {
case *ast.Field: case *ast.Field:
...@@ -122,7 +134,12 @@ func (obj *Var) GetPos() token.Pos { ...@@ -122,7 +134,12 @@ func (obj *Var) GetPos() token.Pos {
} }
return token.NoPos return token.NoPos
} }
func (obj *Func) GetPos() token.Pos { return obj.decl.Name.Pos() } func (obj *Func) GetPos() token.Pos {
if obj.decl != nil && obj.decl.Name != nil {
return obj.decl.Name.Pos()
}
return token.NoPos
}
func (*Package) anObject() {} func (*Package) anObject() {}
func (*Const) anObject() {} func (*Const) anObject() {}
......
...@@ -11,7 +11,7 @@ import ( ...@@ -11,7 +11,7 @@ import (
"strconv" "strconv"
) )
func (check *checker) declareObj(scope, altScope *Scope, obj Object) { func (check *checker) declareObj(scope, altScope *Scope, obj Object, dotImport token.Pos) {
alt := scope.Insert(obj) alt := scope.Insert(obj)
if alt == nil && altScope != nil { if alt == nil && altScope != nil {
// see if there is a conflicting declaration in altScope // see if there is a conflicting declaration in altScope
...@@ -19,8 +19,22 @@ func (check *checker) declareObj(scope, altScope *Scope, obj Object) { ...@@ -19,8 +19,22 @@ func (check *checker) declareObj(scope, altScope *Scope, obj Object) {
} }
if alt != nil { if alt != nil {
prevDecl := "" prevDecl := ""
// for dot-imports, local declarations are declared first - swap messages
if dotImport.IsValid() {
if pos := alt.GetPos(); pos.IsValid() { if pos := alt.GetPos(); pos.IsValid() {
prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", check.fset.Position(pos)) check.errorf(pos, fmt.Sprintf("%s redeclared in this block by dot-import at %s",
obj.GetName(), check.fset.Position(dotImport)))
return
}
// get by w/o other position
check.errorf(dotImport, fmt.Sprintf("dot-import redeclares %s", obj.GetName()))
return
}
if pos := alt.GetPos(); pos.IsValid() {
prevDecl = fmt.Sprintf("\n\tother declaration at %s", check.fset.Position(pos))
} }
check.errorf(obj.GetPos(), fmt.Sprintf("%s redeclared in this block%s", obj.GetName(), prevDecl)) check.errorf(obj.GetPos(), fmt.Sprintf("%s redeclared in this block%s", obj.GetName(), prevDecl))
} }
...@@ -137,7 +151,12 @@ func (check *checker) resolve(importer Importer) (methods []*ast.FuncDecl) { ...@@ -137,7 +151,12 @@ func (check *checker) resolve(importer Importer) (methods []*ast.FuncDecl) {
if name == "." { if name == "." {
// merge imported scope with file scope // merge imported scope with file scope
for _, obj := range imp.Scope.Entries { for _, obj := range imp.Scope.Entries {
check.declareObj(fileScope, pkg.Scope, obj) // gcimported package scopes contain non-exported
// objects such as types used in partially exported
// objects - do not accept them
if ast.IsExported(obj.GetName()) {
check.declareObj(fileScope, pkg.Scope, obj, spec.Pos())
}
} }
// TODO(gri) consider registering the "." identifier // TODO(gri) consider registering the "." identifier
// if we have Context.Ident callbacks for say blank // if we have Context.Ident callbacks for say blank
...@@ -149,7 +168,7 @@ func (check *checker) resolve(importer Importer) (methods []*ast.FuncDecl) { ...@@ -149,7 +168,7 @@ func (check *checker) resolve(importer Importer) (methods []*ast.FuncDecl) {
// a new object instead; the Decl field is different // a new object instead; the Decl field is different
// for different files) // for different files)
obj := &Package{Name: name, Scope: imp.Scope, spec: spec} obj := &Package{Name: name, Scope: imp.Scope, spec: spec}
check.declareObj(fileScope, pkg.Scope, obj) check.declareObj(fileScope, pkg.Scope, obj, token.NoPos)
} }
} }
......
...@@ -11,8 +11,18 @@ import ( ...@@ -11,8 +11,18 @@ import (
// we can have multiple blank imports (was bug) // we can have multiple blank imports (was bug)
_ "math" _ "math"
_ "net/rpc" _ "net/rpc"
// reflect defines a type "flag" which shows up in the gc export data
"reflect"
. "reflect"
) )
// reflect.flag must not be visible in this package
type flag int
type _ reflect /* ERROR "cannot refer to unexported" */ .flag
// dot-imported exported objects may conflict with local objects
type Value /* ERROR "redeclared in this block by dot-import" */ struct{}
const pi = 3.1415 const pi = 3.1415
type ( type (
......
...@@ -64,7 +64,7 @@ var ( ...@@ -64,7 +64,7 @@ var (
t13 int = a /* ERROR "shifted operand" */ << d t13 int = a /* ERROR "shifted operand" */ << d
t14 int = i << j /* ERROR "must be unsigned" */ t14 int = i << j /* ERROR "must be unsigned" */
t15 math /* ERROR "not in selector" */ t15 math /* ERROR "not in selector" */
t16 math.xxx /* ERROR "unexported" */ t16 math /* ERROR "unexported" */ .xxx
t17 math /* ERROR "not a type" */ .Pi t17 math /* ERROR "not a type" */ .Pi
t18 float64 = math.Pi * 10.0 t18 float64 = math.Pi * 10.0
t19 int = t1 /* ERROR "cannot call" */ () t19 int = t1 /* ERROR "cannot call" */ ()
......
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