Commit 574fc66b authored by Robert Griesemer's avatar Robert Griesemer

go/types: add lookup method to context and factor out LookupParent calls

R=go1.11

Also: Moved Checker.pos field into context where it belongs.

This is a cleanup/code factoring.

For #22992.

Change-Id: If9d4f0af537cb181f73735e709ebc8258b2a1378
Reviewed-on: https://go-review.googlesource.com/83017Reviewed-by: default avatarAlan Donovan <adonovan@google.com>
parent dd448957
...@@ -314,7 +314,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) { ...@@ -314,7 +314,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
// can only appear in qualified identifiers which are mapped to // can only appear in qualified identifiers which are mapped to
// selector expressions. // selector expressions.
if ident, ok := e.X.(*ast.Ident); ok { if ident, ok := e.X.(*ast.Ident); ok {
_, obj := check.scope.LookupParent(ident.Name, check.pos) obj := check.lookup(ident.Name)
if pname, _ := obj.(*PkgName); pname != nil { if pname, _ := obj.(*PkgName); pname != nil {
assert(pname.pkg == check.pkg) assert(pname.pkg == check.pkg)
check.recordUse(ident, pname) check.recordUse(ident, pname)
......
...@@ -51,12 +51,19 @@ type funcInfo struct { ...@@ -51,12 +51,19 @@ type funcInfo struct {
type context struct { type context struct {
decl *declInfo // package-level declaration whose init expression/function body is checked decl *declInfo // package-level declaration whose init expression/function body is checked
scope *Scope // top-most scope for lookups scope *Scope // top-most scope for lookups
pos token.Pos // if valid, identifiers are looked up as if at position pos (used by Eval)
iota constant.Value // value of iota in a constant declaration; nil otherwise iota constant.Value // value of iota in a constant declaration; nil otherwise
sig *Signature // function signature if inside a function; nil otherwise sig *Signature // function signature if inside a function; nil otherwise
hasLabel bool // set if a function makes use of labels (only ~1% of functions); unused outside functions hasLabel bool // set if a function makes use of labels (only ~1% of functions); unused outside functions
hasCallOrRecv bool // set if an expression contains a function call or channel receive operation hasCallOrRecv bool // set if an expression contains a function call or channel receive operation
} }
// lookup looks up name in the current context and returns the matching object, or nil.
func (ctxt *context) lookup(name string) Object {
_, obj := ctxt.scope.LookupParent(name, ctxt.pos)
return obj
}
// An importKey identifies an imported package by import path and source directory // An importKey identifies an imported package by import path and source directory
// (directory containing the file containing the import). In practice, the directory // (directory containing the file containing the import). In practice, the directory
// may always be the same, or may not matter. Given an (import path, directory), an // may always be the same, or may not matter. Given an (import path, directory), an
...@@ -95,7 +102,6 @@ type Checker struct { ...@@ -95,7 +102,6 @@ type Checker struct {
// context within which the current object is type-checked // context within which the current object is type-checked
// (valid only for the duration of type-checking a specific object) // (valid only for the duration of type-checking a specific object)
context context
pos token.Pos // if valid, identifiers are looked up as if at position pos (used by Eval)
// debugging // debugging
indent int // indentation for tracing indent int // indentation for tracing
......
...@@ -288,7 +288,7 @@ func (check *Checker) infoFromTypeName(name *ast.Ident, path []*TypeName) *iface ...@@ -288,7 +288,7 @@ func (check *Checker) infoFromTypeName(name *ast.Ident, path []*TypeName) *iface
typenameLoop: typenameLoop:
// name must be a type name denoting a type whose underlying type is an interface // name must be a type name denoting a type whose underlying type is an interface
_, obj := check.scope.LookupParent(name.Name, check.pos /* use Eval position, if any */) obj := check.lookup(name.Name)
if obj == nil { if obj == nil {
return nil return nil
} }
...@@ -363,7 +363,7 @@ func (check *Checker) infoFromQualifiedTypeName(qname *ast.SelectorExpr) *ifaceI ...@@ -363,7 +363,7 @@ func (check *Checker) infoFromQualifiedTypeName(qname *ast.SelectorExpr) *ifaceI
if name == nil { if name == nil {
return nil return nil
} }
_, obj1 := check.scope.LookupParent(name.Name, check.pos /* use Eval position, if any */) obj1 := check.lookup(name.Name)
if obj1 == nil { if obj1 == nil {
return nil return nil
} }
......
...@@ -440,7 +440,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { ...@@ -440,7 +440,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
// list in a "return" statement if a different entity (constant, type, or variable) // list in a "return" statement if a different entity (constant, type, or variable)
// with the same name as a result parameter is in scope at the place of the return." // with the same name as a result parameter is in scope at the place of the return."
for _, obj := range res.vars { for _, obj := range res.vars {
if _, alt := check.scope.LookupParent(obj.name, check.pos); alt != nil && alt != obj { if alt := check.lookup(obj.name); alt != nil && alt != obj {
check.errorf(s.Pos(), "result parameter %s not in scope at return", obj.name) check.errorf(s.Pos(), "result parameter %s not in scope at return", obj.name)
check.errorf(alt.Pos(), "\tinner declaration of %s", obj) check.errorf(alt.Pos(), "\tinner declaration of %s", obj)
// ok to continue // ok to continue
......
...@@ -22,6 +22,8 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeNa ...@@ -22,6 +22,8 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeNa
x.mode = invalid x.mode = invalid
x.expr = e x.expr = e
// Note that we cannot use check.lookup here because the returned scope
// may be different from obj.Parent(). See also Scope.LookupParent doc.
scope, obj := check.scope.LookupParent(e.Name, check.pos) scope, obj := check.scope.LookupParent(e.Name, check.pos)
if obj == nil { if obj == nil {
if e.Name == "_" { if e.Name == "_" {
......
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