}
check.cleaners = nil
}
-
-func (check *Checker) record(x *operand) {
- // convert x into a user-friendly set of values
- // TODO(gri) this code can be simplified
- var typ Type
- var val constant.Value
- switch x.mode {
- case invalid:
- typ = Typ[Invalid]
- case novalue:
- typ = (*Tuple)(nil)
- case constant_:
- typ = x.typ
- val = x.val
- default:
- typ = x.typ
- }
- assert(x.expr != nil && typ != nil)
-
- if isUntyped(typ) {
- // delay type and value recording until we know the type
- // or until the end of type checking
- check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
- } else {
- check.recordTypeAndValue(x.expr, x.mode, typ, val)
- }
-}
-
-func (check *Checker) recordUntyped() {
- if !debug && !check.recordTypes() {
- return // nothing to do
- }
-
- for x, info := range check.untyped {
- if debug && isTyped(info.typ) {
- check.dump("%v: %s (type %s) is typed", atPos(x), x, info.typ)
- panic("unreachable")
- }
- check.recordTypeAndValue(x, info.mode, info.typ, info.val)
- }
-}
-
-func (check *Checker) recordTypeAndValue(x syntax.Expr, mode operandMode, typ Type, val constant.Value) {
- assert(x != nil)
- assert(typ != nil)
- if mode == invalid {
- return // omit
- }
- if mode == constant_ {
- assert(val != nil)
- // We check allBasic(typ, IsConstType) here as constant expressions may be
- // recorded as type parameters.
- assert(!isValid(typ) || allBasic(typ, IsConstType))
- }
- if m := check.Types; m != nil {
- m[x] = TypeAndValue{mode, typ, val}
- }
- if check.StoreTypesInSyntax {
- tv := TypeAndValue{mode, typ, val}
- stv := syntax.TypeAndValue{Type: typ, Value: val}
- if tv.IsVoid() {
- stv.SetIsVoid()
- }
- if tv.IsType() {
- stv.SetIsType()
- }
- if tv.IsBuiltin() {
- stv.SetIsBuiltin()
- }
- if tv.IsValue() {
- stv.SetIsValue()
- }
- if tv.IsNil() {
- stv.SetIsNil()
- }
- if tv.Addressable() {
- stv.SetAddressable()
- }
- if tv.Assignable() {
- stv.SetAssignable()
- }
- if tv.HasOk() {
- stv.SetHasOk()
- }
- x.SetTypeInfo(stv)
- }
-}
-
-func (check *Checker) recordBuiltinType(f syntax.Expr, sig *Signature) {
- // f must be a (possibly parenthesized, possibly qualified)
- // identifier denoting a built-in (including unsafe's non-constant
- // functions Add and Slice): record the signature for f and possible
- // children.
- for {
- check.recordTypeAndValue(f, builtin, sig, nil)
- switch p := f.(type) {
- case *syntax.Name, *syntax.SelectorExpr:
- return // we're done
- case *syntax.ParenExpr:
- f = p.X
- default:
- panic("unreachable")
- }
- }
-}
-
-// recordCommaOkTypes updates recorded types to reflect that x is used in a commaOk context
-// (and therefore has tuple type).
-func (check *Checker) recordCommaOkTypes(x syntax.Expr, a []*operand) {
- assert(x != nil)
- assert(len(a) == 2)
- if a[0].mode == invalid {
- return
- }
- t0, t1 := a[0].typ, a[1].typ
- assert(isTyped(t0) && isTyped(t1) && (allBoolean(t1) || t1 == universeError))
- if m := check.Types; m != nil {
- for {
- tv := m[x]
- assert(tv.Type != nil) // should have been recorded already
- pos := x.Pos()
- tv.Type = NewTuple(
- NewVar(pos, check.pkg, "", t0),
- NewVar(pos, check.pkg, "", t1),
- )
- m[x] = tv
- // if x is a parenthesized expression (p.X), update p.X
- p, _ := x.(*syntax.ParenExpr)
- if p == nil {
- break
- }
- x = p.X
- }
- }
- if check.StoreTypesInSyntax {
- // Note: this loop is duplicated because the type of tv is different.
- // Above it is types2.TypeAndValue, here it is syntax.TypeAndValue.
- for {
- tv := x.GetTypeInfo()
- assert(tv.Type != nil) // should have been recorded already
- pos := x.Pos()
- tv.Type = NewTuple(
- NewVar(pos, check.pkg, "", t0),
- NewVar(pos, check.pkg, "", t1),
- )
- x.SetTypeInfo(tv)
- p, _ := x.(*syntax.ParenExpr)
- if p == nil {
- break
- }
- x = p.X
- }
- }
-}
-
-// recordInstance records instantiation information into check.Info, if the
-// Instances map is non-nil. The given expr must be an ident, selector, or
-// index (list) expr with ident or selector operand.
-//
-// TODO(rfindley): the expr parameter is fragile. See if we can access the
-// instantiated identifier in some other way.
-func (check *Checker) recordInstance(expr syntax.Expr, targs []Type, typ Type) {
- ident := instantiatedIdent(expr)
- assert(ident != nil)
- assert(typ != nil)
- if m := check.Instances; m != nil {
- m[ident] = Instance{newTypeList(targs), typ}
- }
-}
-
-func instantiatedIdent(expr syntax.Expr) *syntax.Name {
- var selOrIdent syntax.Expr
- switch e := expr.(type) {
- case *syntax.IndexExpr:
- selOrIdent = e.X
- case *syntax.SelectorExpr, *syntax.Name:
- selOrIdent = e
- }
- switch x := selOrIdent.(type) {
- case *syntax.Name:
- return x
- case *syntax.SelectorExpr:
- return x.Sel
- }
- panic("instantiated ident not found")
-}
-
-func (check *Checker) recordDef(id *syntax.Name, obj Object) {
- assert(id != nil)
- if m := check.Defs; m != nil {
- m[id] = obj
- }
-}
-
-func (check *Checker) recordUse(id *syntax.Name, obj Object) {
- assert(id != nil)
- assert(obj != nil)
- if m := check.Uses; m != nil {
- m[id] = obj
- }
-}
-
-func (check *Checker) recordImplicit(node syntax.Node, obj Object) {
- assert(node != nil)
- assert(obj != nil)
- if m := check.Implicits; m != nil {
- m[node] = obj
- }
-}
-
-func (check *Checker) recordSelection(x *syntax.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
- assert(obj != nil && (recv == nil || len(index) > 0))
- check.recordUse(x.Sel, obj)
- if m := check.Selections; m != nil {
- m[x] = &Selection{kind, recv, obj, index, indirect}
- }
-}
-
-func (check *Checker) recordScope(node syntax.Node, scope *Scope) {
- assert(node != nil)
- assert(scope != nil)
- if m := check.Scopes; m != nil {
- m[node] = scope
- }
-}
--- /dev/null
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements recording of type information
+// in the types2.Info maps.
+
+package types2
+
+import (
+ "cmd/compile/internal/syntax"
+ "go/constant"
+)
+
+func (check *Checker) record(x *operand) {
+ // convert x into a user-friendly set of values
+ // TODO(gri) this code can be simplified
+ var typ Type
+ var val constant.Value
+ switch x.mode {
+ case invalid:
+ typ = Typ[Invalid]
+ case novalue:
+ typ = (*Tuple)(nil)
+ case constant_:
+ typ = x.typ
+ val = x.val
+ default:
+ typ = x.typ
+ }
+ assert(x.expr != nil && typ != nil)
+
+ if isUntyped(typ) {
+ // delay type and value recording until we know the type
+ // or until the end of type checking
+ check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
+ } else {
+ check.recordTypeAndValue(x.expr, x.mode, typ, val)
+ }
+}
+
+func (check *Checker) recordUntyped() {
+ if !debug && !check.recordTypes() {
+ return // nothing to do
+ }
+
+ for x, info := range check.untyped {
+ if debug && isTyped(info.typ) {
+ check.dump("%v: %s (type %s) is typed", atPos(x), x, info.typ)
+ panic("unreachable")
+ }
+ check.recordTypeAndValue(x, info.mode, info.typ, info.val)
+ }
+}
+
+func (check *Checker) recordTypeAndValue(x syntax.Expr, mode operandMode, typ Type, val constant.Value) {
+ assert(x != nil)
+ assert(typ != nil)
+ if mode == invalid {
+ return // omit
+ }
+ if mode == constant_ {
+ assert(val != nil)
+ // We check allBasic(typ, IsConstType) here as constant expressions may be
+ // recorded as type parameters.
+ assert(!isValid(typ) || allBasic(typ, IsConstType))
+ }
+ if m := check.Types; m != nil {
+ m[x] = TypeAndValue{mode, typ, val}
+ }
+ if check.StoreTypesInSyntax {
+ tv := TypeAndValue{mode, typ, val}
+ stv := syntax.TypeAndValue{Type: typ, Value: val}
+ if tv.IsVoid() {
+ stv.SetIsVoid()
+ }
+ if tv.IsType() {
+ stv.SetIsType()
+ }
+ if tv.IsBuiltin() {
+ stv.SetIsBuiltin()
+ }
+ if tv.IsValue() {
+ stv.SetIsValue()
+ }
+ if tv.IsNil() {
+ stv.SetIsNil()
+ }
+ if tv.Addressable() {
+ stv.SetAddressable()
+ }
+ if tv.Assignable() {
+ stv.SetAssignable()
+ }
+ if tv.HasOk() {
+ stv.SetHasOk()
+ }
+ x.SetTypeInfo(stv)
+ }
+}
+
+func (check *Checker) recordBuiltinType(f syntax.Expr, sig *Signature) {
+ // f must be a (possibly parenthesized, possibly qualified)
+ // identifier denoting a built-in (including unsafe's non-constant
+ // functions Add and Slice): record the signature for f and possible
+ // children.
+ for {
+ check.recordTypeAndValue(f, builtin, sig, nil)
+ switch p := f.(type) {
+ case *syntax.Name, *syntax.SelectorExpr:
+ return // we're done
+ case *syntax.ParenExpr:
+ f = p.X
+ default:
+ panic("unreachable")
+ }
+ }
+}
+
+// recordCommaOkTypes updates recorded types to reflect that x is used in a commaOk context
+// (and therefore has tuple type).
+func (check *Checker) recordCommaOkTypes(x syntax.Expr, a []*operand) {
+ assert(x != nil)
+ assert(len(a) == 2)
+ if a[0].mode == invalid {
+ return
+ }
+ t0, t1 := a[0].typ, a[1].typ
+ assert(isTyped(t0) && isTyped(t1) && (allBoolean(t1) || t1 == universeError))
+ if m := check.Types; m != nil {
+ for {
+ tv := m[x]
+ assert(tv.Type != nil) // should have been recorded already
+ pos := x.Pos()
+ tv.Type = NewTuple(
+ NewVar(pos, check.pkg, "", t0),
+ NewVar(pos, check.pkg, "", t1),
+ )
+ m[x] = tv
+ // if x is a parenthesized expression (p.X), update p.X
+ p, _ := x.(*syntax.ParenExpr)
+ if p == nil {
+ break
+ }
+ x = p.X
+ }
+ }
+ if check.StoreTypesInSyntax {
+ // Note: this loop is duplicated because the type of tv is different.
+ // Above it is types2.TypeAndValue, here it is syntax.TypeAndValue.
+ for {
+ tv := x.GetTypeInfo()
+ assert(tv.Type != nil) // should have been recorded already
+ pos := x.Pos()
+ tv.Type = NewTuple(
+ NewVar(pos, check.pkg, "", t0),
+ NewVar(pos, check.pkg, "", t1),
+ )
+ x.SetTypeInfo(tv)
+ p, _ := x.(*syntax.ParenExpr)
+ if p == nil {
+ break
+ }
+ x = p.X
+ }
+ }
+}
+
+// recordInstance records instantiation information into check.Info, if the
+// Instances map is non-nil. The given expr must be an ident, selector, or
+// index (list) expr with ident or selector operand.
+//
+// TODO(rfindley): the expr parameter is fragile. See if we can access the
+// instantiated identifier in some other way.
+func (check *Checker) recordInstance(expr syntax.Expr, targs []Type, typ Type) {
+ ident := instantiatedIdent(expr)
+ assert(ident != nil)
+ assert(typ != nil)
+ if m := check.Instances; m != nil {
+ m[ident] = Instance{newTypeList(targs), typ}
+ }
+}
+
+func instantiatedIdent(expr syntax.Expr) *syntax.Name {
+ var selOrIdent syntax.Expr
+ switch e := expr.(type) {
+ case *syntax.IndexExpr:
+ selOrIdent = e.X
+ case *syntax.SelectorExpr, *syntax.Name:
+ selOrIdent = e
+ }
+ switch x := selOrIdent.(type) {
+ case *syntax.Name:
+ return x
+ case *syntax.SelectorExpr:
+ return x.Sel
+ }
+ panic("instantiated ident not found")
+}
+
+func (check *Checker) recordDef(id *syntax.Name, obj Object) {
+ assert(id != nil)
+ if m := check.Defs; m != nil {
+ m[id] = obj
+ }
+}
+
+func (check *Checker) recordUse(id *syntax.Name, obj Object) {
+ assert(id != nil)
+ assert(obj != nil)
+ if m := check.Uses; m != nil {
+ m[id] = obj
+ }
+}
+
+func (check *Checker) recordImplicit(node syntax.Node, obj Object) {
+ assert(node != nil)
+ assert(obj != nil)
+ if m := check.Implicits; m != nil {
+ m[node] = obj
+ }
+}
+
+func (check *Checker) recordSelection(x *syntax.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
+ assert(obj != nil && (recv == nil || len(index) > 0))
+ check.recordUse(x.Sel, obj)
+ if m := check.Selections; m != nil {
+ m[x] = &Selection{kind, recv, obj, index, indirect}
+ }
+}
+
+func (check *Checker) recordScope(node syntax.Node, scope *Scope) {
+ assert(node != nil)
+ assert(scope != nil)
+ if m := check.Scopes; m != nil {
+ m[node] = scope
+ }
+}
"go/token"
"internal/godebug"
. "internal/types/errors"
- "strings"
"sync/atomic"
)
}
check.cleaners = nil
}
-
-func (check *Checker) record(x *operand) {
- // convert x into a user-friendly set of values
- // TODO(gri) this code can be simplified
- var typ Type
- var val constant.Value
- switch x.mode {
- case invalid:
- typ = Typ[Invalid]
- case novalue:
- typ = (*Tuple)(nil)
- case constant_:
- typ = x.typ
- val = x.val
- default:
- typ = x.typ
- }
- assert(x.expr != nil && typ != nil)
-
- if isUntyped(typ) {
- // delay type and value recording until we know the type
- // or until the end of type checking
- check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
- } else {
- check.recordTypeAndValue(x.expr, x.mode, typ, val)
- }
-}
-
-func (check *Checker) recordUntyped() {
- if !debug && check.Types == nil {
- return // nothing to do
- }
-
- for x, info := range check.untyped {
- if debug && isTyped(info.typ) {
- check.dump("%v: %s (type %s) is typed", x.Pos(), x, info.typ)
- panic("unreachable")
- }
- check.recordTypeAndValue(x, info.mode, info.typ, info.val)
- }
-}
-
-func (check *Checker) recordTypeAndValue(x ast.Expr, mode operandMode, typ Type, val constant.Value) {
- assert(x != nil)
- assert(typ != nil)
- if mode == invalid {
- return // omit
- }
- if mode == constant_ {
- assert(val != nil)
- // We check allBasic(typ, IsConstType) here as constant expressions may be
- // recorded as type parameters.
- assert(!isValid(typ) || allBasic(typ, IsConstType))
- }
- if m := check.Types; m != nil {
- m[x] = TypeAndValue{mode, typ, val}
- }
-}
-
-func (check *Checker) recordBuiltinType(f ast.Expr, sig *Signature) {
- // f must be a (possibly parenthesized, possibly qualified)
- // identifier denoting a built-in (including unsafe's non-constant
- // functions Add and Slice): record the signature for f and possible
- // children.
- for {
- check.recordTypeAndValue(f, builtin, sig, nil)
- switch p := f.(type) {
- case *ast.Ident, *ast.SelectorExpr:
- return // we're done
- case *ast.ParenExpr:
- f = p.X
- default:
- panic("unreachable")
- }
- }
-}
-
-// recordCommaOkTypes updates recorded types to reflect that x is used in a commaOk context
-// (and therefore has tuple type).
-func (check *Checker) recordCommaOkTypes(x ast.Expr, a []*operand) {
- assert(x != nil)
- assert(len(a) == 2)
- if a[0].mode == invalid {
- return
- }
- t0, t1 := a[0].typ, a[1].typ
- assert(isTyped(t0) && isTyped(t1) && (allBoolean(t1) || t1 == universeError))
- if m := check.Types; m != nil {
- for {
- tv := m[x]
- assert(tv.Type != nil) // should have been recorded already
- pos := x.Pos()
- tv.Type = NewTuple(
- NewVar(pos, check.pkg, "", t0),
- NewVar(pos, check.pkg, "", t1),
- )
- m[x] = tv
- // if x is a parenthesized expression (p.X), update p.X
- p, _ := x.(*ast.ParenExpr)
- if p == nil {
- break
- }
- x = p.X
- }
- }
-}
-
-// recordInstance records instantiation information into check.Info, if the
-// Instances map is non-nil. The given expr must be an ident, selector, or
-// index (list) expr with ident or selector operand.
-//
-// TODO(rfindley): the expr parameter is fragile. See if we can access the
-// instantiated identifier in some other way.
-func (check *Checker) recordInstance(expr ast.Expr, targs []Type, typ Type) {
- ident := instantiatedIdent(expr)
- assert(ident != nil)
- assert(typ != nil)
- if m := check.Instances; m != nil {
- m[ident] = Instance{newTypeList(targs), typ}
- }
-}
-
-func instantiatedIdent(expr ast.Expr) *ast.Ident {
- var selOrIdent ast.Expr
- switch e := expr.(type) {
- case *ast.IndexExpr:
- selOrIdent = e.X
- case *ast.IndexListExpr:
- selOrIdent = e.X
- case *ast.SelectorExpr, *ast.Ident:
- selOrIdent = e
- }
- switch x := selOrIdent.(type) {
- case *ast.Ident:
- return x
- case *ast.SelectorExpr:
- return x.Sel
- }
-
- // extra debugging of #63933
- var buf strings.Builder
- buf.WriteString("instantiated ident not found; please report: ")
- ast.Fprint(&buf, token.NewFileSet(), expr, ast.NotNilFilter)
- panic(buf.String())
-}
-
-func (check *Checker) recordDef(id *ast.Ident, obj Object) {
- assert(id != nil)
- if m := check.Defs; m != nil {
- m[id] = obj
- }
-}
-
-func (check *Checker) recordUse(id *ast.Ident, obj Object) {
- assert(id != nil)
- assert(obj != nil)
- if m := check.Uses; m != nil {
- m[id] = obj
- }
-}
-
-func (check *Checker) recordImplicit(node ast.Node, obj Object) {
- assert(node != nil)
- assert(obj != nil)
- if m := check.Implicits; m != nil {
- m[node] = obj
- }
-}
-
-func (check *Checker) recordSelection(x *ast.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
- assert(obj != nil && (recv == nil || len(index) > 0))
- check.recordUse(x.Sel, obj)
- if m := check.Selections; m != nil {
- m[x] = &Selection{kind, recv, obj, index, indirect}
- }
-}
-
-func (check *Checker) recordScope(node ast.Node, scope *Scope) {
- assert(node != nil)
- assert(scope != nil)
- if m := check.Scopes; m != nil {
- m[node] = scope
- }
-}
--- /dev/null
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements recording of type information
+// in the types.Info maps.
+
+package types
+
+import (
+ "go/ast"
+ "go/constant"
+ "go/token"
+ "strings"
+)
+
+func (check *Checker) record(x *operand) {
+ // convert x into a user-friendly set of values
+ // TODO(gri) this code can be simplified
+ var typ Type
+ var val constant.Value
+ switch x.mode {
+ case invalid:
+ typ = Typ[Invalid]
+ case novalue:
+ typ = (*Tuple)(nil)
+ case constant_:
+ typ = x.typ
+ val = x.val
+ default:
+ typ = x.typ
+ }
+ assert(x.expr != nil && typ != nil)
+
+ if isUntyped(typ) {
+ // delay type and value recording until we know the type
+ // or until the end of type checking
+ check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
+ } else {
+ check.recordTypeAndValue(x.expr, x.mode, typ, val)
+ }
+}
+
+func (check *Checker) recordUntyped() {
+ if !debug && check.Types == nil {
+ return // nothing to do
+ }
+
+ for x, info := range check.untyped {
+ if debug && isTyped(info.typ) {
+ check.dump("%v: %s (type %s) is typed", x.Pos(), x, info.typ)
+ panic("unreachable")
+ }
+ check.recordTypeAndValue(x, info.mode, info.typ, info.val)
+ }
+}
+
+func (check *Checker) recordTypeAndValue(x ast.Expr, mode operandMode, typ Type, val constant.Value) {
+ assert(x != nil)
+ assert(typ != nil)
+ if mode == invalid {
+ return // omit
+ }
+ if mode == constant_ {
+ assert(val != nil)
+ // We check allBasic(typ, IsConstType) here as constant expressions may be
+ // recorded as type parameters.
+ assert(!isValid(typ) || allBasic(typ, IsConstType))
+ }
+ if m := check.Types; m != nil {
+ m[x] = TypeAndValue{mode, typ, val}
+ }
+}
+
+func (check *Checker) recordBuiltinType(f ast.Expr, sig *Signature) {
+ // f must be a (possibly parenthesized, possibly qualified)
+ // identifier denoting a built-in (including unsafe's non-constant
+ // functions Add and Slice): record the signature for f and possible
+ // children.
+ for {
+ check.recordTypeAndValue(f, builtin, sig, nil)
+ switch p := f.(type) {
+ case *ast.Ident, *ast.SelectorExpr:
+ return // we're done
+ case *ast.ParenExpr:
+ f = p.X
+ default:
+ panic("unreachable")
+ }
+ }
+}
+
+// recordCommaOkTypes updates recorded types to reflect that x is used in a commaOk context
+// (and therefore has tuple type).
+func (check *Checker) recordCommaOkTypes(x ast.Expr, a []*operand) {
+ assert(x != nil)
+ assert(len(a) == 2)
+ if a[0].mode == invalid {
+ return
+ }
+ t0, t1 := a[0].typ, a[1].typ
+ assert(isTyped(t0) && isTyped(t1) && (allBoolean(t1) || t1 == universeError))
+ if m := check.Types; m != nil {
+ for {
+ tv := m[x]
+ assert(tv.Type != nil) // should have been recorded already
+ pos := x.Pos()
+ tv.Type = NewTuple(
+ NewVar(pos, check.pkg, "", t0),
+ NewVar(pos, check.pkg, "", t1),
+ )
+ m[x] = tv
+ // if x is a parenthesized expression (p.X), update p.X
+ p, _ := x.(*ast.ParenExpr)
+ if p == nil {
+ break
+ }
+ x = p.X
+ }
+ }
+}
+
+// recordInstance records instantiation information into check.Info, if the
+// Instances map is non-nil. The given expr must be an ident, selector, or
+// index (list) expr with ident or selector operand.
+//
+// TODO(rfindley): the expr parameter is fragile. See if we can access the
+// instantiated identifier in some other way.
+func (check *Checker) recordInstance(expr ast.Expr, targs []Type, typ Type) {
+ ident := instantiatedIdent(expr)
+ assert(ident != nil)
+ assert(typ != nil)
+ if m := check.Instances; m != nil {
+ m[ident] = Instance{newTypeList(targs), typ}
+ }
+}
+
+func instantiatedIdent(expr ast.Expr) *ast.Ident {
+ var selOrIdent ast.Expr
+ switch e := expr.(type) {
+ case *ast.IndexExpr:
+ selOrIdent = e.X
+ case *ast.IndexListExpr:
+ selOrIdent = e.X
+ case *ast.SelectorExpr, *ast.Ident:
+ selOrIdent = e
+ }
+ switch x := selOrIdent.(type) {
+ case *ast.Ident:
+ return x
+ case *ast.SelectorExpr:
+ return x.Sel
+ }
+
+ // extra debugging of #63933
+ var buf strings.Builder
+ buf.WriteString("instantiated ident not found; please report: ")
+ ast.Fprint(&buf, token.NewFileSet(), expr, ast.NotNilFilter)
+ panic(buf.String())
+}
+
+func (check *Checker) recordDef(id *ast.Ident, obj Object) {
+ assert(id != nil)
+ if m := check.Defs; m != nil {
+ m[id] = obj
+ }
+}
+
+func (check *Checker) recordUse(id *ast.Ident, obj Object) {
+ assert(id != nil)
+ assert(obj != nil)
+ if m := check.Uses; m != nil {
+ m[id] = obj
+ }
+}
+
+func (check *Checker) recordImplicit(node ast.Node, obj Object) {
+ assert(node != nil)
+ assert(obj != nil)
+ if m := check.Implicits; m != nil {
+ m[node] = obj
+ }
+}
+
+func (check *Checker) recordSelection(x *ast.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
+ assert(obj != nil && (recv == nil || len(index) > 0))
+ check.recordUse(x.Sel, obj)
+ if m := check.Selections; m != nil {
+ m[x] = &Selection{kind, recv, obj, index, indirect}
+ }
+}
+
+func (check *Checker) recordScope(node ast.Node, scope *Scope) {
+ assert(node != nil)
+ assert(scope != nil)
+ if m := check.Scopes; m != nil {
+ m[node] = scope
+ }
+}