hasCallOrRecv bool // set if an expression contains a function call or channel receive operation
}
-// lookup looks up name in the current environment and returns the matching object, or nil.
+// lookupScope looks up name in the current environment and if an object
+// is found it returns the scope containing the object and the object.
+// Otherwise it returns (nil, nil).
+//
+// Note that obj.Parent() may be different from the returned scope if the
+// object was inserted into the scope and already had a parent at that
+// time (see Scope.Insert). This can only happen for dot-imported objects
+// whose parent is the scope of the package that exported them.
+func (env *environment) lookupScope(name string) (*Scope, Object) {
+ for s := env.scope; s != nil; s = s.parent {
+ if obj := s.Lookup(name); obj != nil && (!env.pos.IsKnown() || cmpPos(obj.scopePos(), env.pos) <= 0) {
+ return s, obj
+ }
+ }
+ return nil, nil
+}
+
+// lookup is like lookupScope but it only returns the object (or nil).
func (env *environment) lookup(name string) Object {
- _, obj := env.scope.LookupParent(name, env.pos)
+ _, obj := env.lookupScope(name)
return obj
}
// Note that obj.Parent() may be different from the returned scope if the
// object was inserted into the scope and already had a parent at that
// time (see Insert). This can only happen for dot-imported objects
-// whose scope is the scope of the package that exported them.
+// whose parent is the scope of the package that exported them.
func (s *Scope) LookupParent(name string, pos syntax.Pos) (*Scope, Object) {
for ; s != nil; s = s.parent {
if obj := s.Lookup(name); obj != nil && (!pos.IsKnown() || cmpPos(obj.scopePos(), pos) <= 0) {
return alt
}
s.insert(name, obj)
+ // TODO(gri) Can we always set the parent to s (or is there
+ // a need to keep the original parent or some race condition)?
+ // If we can, than we may not need environment.lookupScope
+ // which is only there so that we get the correct scope for
+ // marking "used" dot-imported packages.
if obj.Parent() == nil {
obj.setParent(s)
}
x.mode = invalid
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.Value, check.pos)
+ scope, obj := check.lookupScope(e.Value)
switch obj {
case nil:
if e.Value == "_" {
hasCallOrRecv bool // set if an expression contains a function call or channel receive operation
}
-// lookup looks up name in the current environment and returns the matching object, or nil.
+// lookupScope looks up name in the current environment and if an object
+// is found it returns the scope containing the object and the object.
+// Otherwise it returns (nil, nil).
+//
+// Note that obj.Parent() may be different from the returned scope if the
+// object was inserted into the scope and already had a parent at that
+// time (see Scope.Insert). This can only happen for dot-imported objects
+// whose parent is the scope of the package that exported them.
+func (env *environment) lookupScope(name string) (*Scope, Object) {
+ for s := env.scope; s != nil; s = s.parent {
+ if obj := s.Lookup(name); obj != nil && (!env.pos.IsValid() || cmpPos(obj.scopePos(), env.pos) <= 0) {
+ return s, obj
+ }
+ }
+ return nil, nil
+}
+
+// lookup is like lookupScope but it only returns the object (or nil).
func (env *environment) lookup(name string) Object {
- _, obj := env.scope.LookupParent(name, env.pos)
+ _, obj := env.lookupScope(name)
return obj
}
// Note that obj.Parent() may be different from the returned scope if the
// object was inserted into the scope and already had a parent at that
// time (see Insert). This can only happen for dot-imported objects
-// whose scope is the scope of the package that exported them.
+// whose parent is the scope of the package that exported them.
func (s *Scope) LookupParent(name string, pos token.Pos) (*Scope, Object) {
for ; s != nil; s = s.parent {
if obj := s.Lookup(name); obj != nil && (!pos.IsValid() || cmpPos(obj.scopePos(), pos) <= 0) {
return alt
}
s.insert(name, obj)
+ // TODO(gri) Can we always set the parent to s (or is there
+ // a need to keep the original parent or some race condition)?
+ // If we can, than we may not need environment.lookupScope
+ // which is only there so that we get the correct scope for
+ // marking "used" dot-imported packages.
if obj.Parent() == nil {
obj.setParent(s)
}
x.mode = invalid
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.lookupScope(e.Name)
switch obj {
case nil:
if e.Name == "_" {