Source File
lookup.go
Belonging Package
go/types
// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.// Source: ../../cmd/compile/internal/types2/lookup.go// Copyright 2013 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 various field and method lookup functions.package typesimport// LookupSelection selects the field or method whose ID is Id(pkg,// name), on a value of type T. If addressable is set, T is the type// of an addressable variable (this matters only for method lookups).// T must not be nil.//// If the selection is valid://// - [Selection.Obj] returns the field ([Var]) or method ([Func]);// - [Selection.Indirect] reports whether there were any pointer// indirections on the path to the field or method.// - [Selection.Index] returns the index sequence, defined below.//// The last index entry is the field or method index in the (possibly// embedded) type where the entry was found, either://// 1. the list of declared methods of a named type; or// 2. the list of all methods (method set) of an interface type; or// 3. the list of fields of a struct type.//// The earlier index entries are the indices of the embedded struct// fields traversed to get to the found entry, starting at depth 0.//// See also [LookupFieldOrMethod], which returns the components separately.func ( Type, bool, *Package, string) (Selection, bool) {, , := LookupFieldOrMethod(, , , )var SelectionKindswitch .(type) {case nil:return Selection{}, falsecase *Func:= MethodValcase *Var:= FieldValdefault:panic() // can't happen}return Selection{, , , , }, true}// Internal use of LookupFieldOrMethod: If the obj result is a method// associated with a concrete (non-interface) type, the method's signature// may not be fully set up. Call Checker.objDecl(obj, nil) before accessing// the method's type.// LookupFieldOrMethod looks up a field or method with given package and name// in T and returns the corresponding *Var or *Func, an index sequence, and a// bool indicating if there were any pointer indirections on the path to the// field or method. If addressable is set, T is the type of an addressable// variable (only matters for method lookups). T must not be nil.//// The last index entry is the field or method index in the (possibly embedded)// type where the entry was found, either://// 1. the list of declared methods of a named type; or// 2. the list of all methods (method set) of an interface type; or// 3. the list of fields of a struct type.//// The earlier index entries are the indices of the embedded struct fields// traversed to get to the found entry, starting at depth 0.//// If no entry is found, a nil object is returned. In this case, the returned// index and indirect values have the following meaning://// - If index != nil, the index sequence points to an ambiguous entry// (the same name appeared more than once at the same embedding level).//// - If indirect is set, a method with a pointer receiver type was found// but there was no pointer on the path from the actual receiver type to// the method's formal receiver base type, nor was the receiver addressable.//// See also [LookupSelection], which returns the result as a [Selection].func ( Type, bool, *Package, string) ( Object, []int, bool) {if == nil {panic("LookupFieldOrMethod on nil type")}return lookupFieldOrMethod(, , , , false)}// lookupFieldOrMethod is like LookupFieldOrMethod but with the additional foldCase parameter// (see Object.sameId for the meaning of foldCase).func lookupFieldOrMethod( Type, bool, *Package, string, bool) ( Object, []int, bool) {// Methods cannot be associated to a named pointer type.// (spec: "The type denoted by T is called the receiver base type;// it must not be a pointer or interface type and it must be declared// in the same package as the method.").// Thus, if we have a named pointer type, proceed with the underlying// pointer type but discard the result if it is a method since we would// not have found it for T (see also go.dev/issue/8590).if := asNamed(); != nil {if , := .Underlying().(*Pointer); != nil {, , = lookupFieldOrMethodImpl(, false, , , )if , := .(*Func); {return nil, nil, false}return}}, , = lookupFieldOrMethodImpl(, , , , )// If we didn't find anything and if we have a type parameter with a common underlying// type, see if there is a matching field (but not a method, those need to be declared// explicitly in the constraint). If the constraint is a named pointer type (see above),// we are ok here because only fields are accepted as results.const = false // see go.dev/issue/51576if && == nil && isTypeParam() {if , := commonUnder(, nil); != nil {, , = lookupFieldOrMethodImpl(, , , , )if , := .(*Var); ! {, , = nil, nil, false // accept fields (variables) only}}}return}// lookupFieldOrMethodImpl is the implementation of lookupFieldOrMethod.// Notably, in contrast to lookupFieldOrMethod, it won't find struct fields// in base types of defined (*Named) pointer types T. For instance, given// the declaration://// type T *struct{f int}//// lookupFieldOrMethodImpl won't find the field f in the defined (*Named) type T// (methods on T are not permitted in the first place).//// Thus, lookupFieldOrMethodImpl should only be called by lookupFieldOrMethod// and missingMethod (the latter doesn't care about struct fields).//// The resulting object may not be fully type-checked.func lookupFieldOrMethodImpl( Type, bool, *Package, string, bool) ( Object, []int, bool) {// WARNING: The code in this function is extremely subtle - do not modify casually!if == "_" {return // blank fields/methods are never found}// Importantly, we must not call under before the call to deref below (nor// does deref call under), as doing so could incorrectly result in finding// methods of the pointer base type when T is a (*Named) pointer type., := deref()// *typ where typ is an interface (incl. a type parameter) has no methods.if {if , := under().(*Interface); {return}}// Start with typ as single entry at shallowest depth.:= []embeddedType{{, nil, , false}}// seen tracks named types that we have seen already, allocated lazily.// Used to avoid endless searches in case of recursive types.//// We must use a lookup on identity rather than a simple map[*Named]bool as// instantiated types may be identical but not equal.var instanceLookup// search current depthfor len() > 0 {var []embeddedType // embedded types found at current depth// look for (pkg, name) in all types at current depthfor , := range {:= .typ// If we have a named type, we may have associated methods.// Look for those first.if := asNamed(); != nil {if := .lookup(); != nil {// We have seen this type before, at a more shallow depth// (note that multiples of this type at the current depth// were consolidated before). The type at that depth shadows// this same type at the current depth, so we can ignore// this one.continue}.add()// look for a matching attached methodif , := .lookupMethod(, , ); != nil {// potential match// caution: method may not have a proper signature yet= concat(.index, )if != nil || .multiples {return nil, , false // collision}== .indirectcontinue // we can't have a matching field or interface method}}switch t := under().(type) {case *Struct:// look for a matching field and collect embedded typesfor , := range .fields {if .sameId(, , ) {assert(.typ != nil)= concat(.index, )if != nil || .multiples {return nil, , false // collision}== .indirectcontinue // we can't have a matching interface method}// Collect embedded struct fields for searching the next// lower depth, but only if we have not seen a match yet// (if we have a match it is either the desired field or// we have a name collision on the same depth; in either// case we don't need to look further).// Embedded fields are always of the form T or *T where// T is a type name. If e.typ appeared multiple times at// this depth, f.typ appears multiple times at the next// depth.if == nil && .embedded {, := deref(.typ)// TODO(gri) optimization: ignore types that can't// have fields or methods (only Named, Struct, and// Interface types need to be considered).= append(, embeddedType{, concat(.index, ), .indirect || , .multiples})}}case *Interface:// look for a matching method (interface may be a type parameter)if , := .typeSet().LookupMethod(, , ); != nil {assert(.typ != nil)= concat(.index, )if != nil || .multiples {return nil, , false // collision}== .indirect}}}if != nil {// found a potential match// spec: "A method call x.m() is valid if the method set of (the type of) x// contains m and the argument list can be assigned to the parameter// list of m. If x is addressable and &x's method set contains m, x.m()// is shorthand for (&x).m()".if , := .(*Func); != nil {// determine if method has a pointer receiverif .hasPtrRecv() && ! && ! {return nil, nil, true // pointer/addressable receiver required}}return}= consolidateMultiples()}return nil, nil, false // not found}// embeddedType represents an embedded typetype embeddedType struct {typ Typeindex []int // embedded field indices, starting with index at depth 0indirect bool // if set, there was a pointer indirection on the path to this fieldmultiples bool // if set, typ appears multiple times at this depth}// consolidateMultiples collects multiple list entries with the same type// into a single entry marked as containing multiples. The result is the// consolidated list.func consolidateMultiples( []embeddedType) []embeddedType {if len() <= 1 {return // at most one entry - nothing to do}:= 0 // number of entries w/ unique type:= make(map[Type]int) // index at which type was previously seenfor , := range {if , := lookupType(, .typ); {[].multiples = true// ignore this entry} else {[.typ] =[] =++}}return [:]}func lookupType( map[Type]int, Type) (int, bool) {// fast path: maybe the types are equalif , := []; {return , true}for , := range {if Identical(, ) {return , true}}return 0, false}type instanceLookup struct {// buf is used to avoid allocating the map m in the common case of a small// number of instances.buf [3]*Namedm map[*Named][]*Named}func ( *instanceLookup) ( *Named) *Named {for , := range .buf {if != nil && Identical(, ) {return}}for , := range .m[.Origin()] {if Identical(, ) {return}}return nil}func ( *instanceLookup) ( *Named) {for , := range .buf {if == nil {.buf[] =return}}if .m == nil {.m = make(map[*Named][]*Named)}:= .m[.Origin()].m[.Origin()] = append(, )}// MissingMethod returns (nil, false) if V implements T, otherwise it// returns a missing method required by T and whether it is missing or// just has the wrong type: either a pointer receiver or wrong signature.//// For non-interface types V, or if static is set, V implements T if all// methods of T are present in V. Otherwise (V is an interface and static// is not set), MissingMethod only checks that methods of T which are also// present in V have matching types (e.g., for a type assertion x.(T) where// x is of interface type V).func ( Type, *Interface, bool) ( *Func, bool) {return (*Checker)(nil).missingMethod(, , , Identical, nil)}// missingMethod is like MissingMethod but accepts a *Checker as receiver,// a comparator equivalent for type comparison, and a *string for error causes.// The receiver may be nil if missingMethod is invoked through an exported// API call (such as MissingMethod), i.e., when all methods have been type-// checked.// The underlying type of T must be an interface; T (rather than its under-// lying type) is used for better error messages (reported through *cause).// The comparator is used to compare signatures.// If a method is missing and cause is not nil, *cause describes the error.func ( *Checker) (, Type, bool, func(, Type) bool, *string) ( *Func, bool) {:= under().(*Interface).typeSet().methods // T must be an interfaceif len() == 0 {return nil, false}const (= iota):=var *Func // method on T we're trying to implementvar *Func // method on V, if found (state is one of ok, wrongName, wrongSig)if , := under().(*Interface); != nil {:= .typeSet()for _, = range {_, = .LookupMethod(.pkg, .name, false)if == nil {if ! {continue}=break}if !(.typ, .typ) {=break}}} else {for _, = range {, , := lookupFieldOrMethodImpl(, false, .pkg, .name, false)// check if m is ambiguous, on *V, or on V with case-foldingif == nil {switch {case != nil:=case :=default:=, _, _ = lookupFieldOrMethodImpl(, false, .pkg, .name, true /* fold case */), _ = .(*Func)if != nil {=if .name == .name {// If the names are equal, f must be unexported// (otherwise the package wouldn't matter).=}}}break}// we must have a method (not a struct field), _ = .(*Func)if == nil {=break}// methods may not have a fully set up signature yetif != nil {.objDecl(, nil)}if !(.typ, .typ) {=break}}}if == {return nil, false}if != nil {if != nil {// This method may be formatted in funcString below, so must have a fully// set up signature.if != nil {.objDecl(, nil)}}switch {case :switch {case isInterfacePtr():* = "(" + .interfacePtrError() + ")"case isInterfacePtr():* = "(" + .interfacePtrError() + ")"default:* = .sprintf("(missing method %s)", .Name())}case :, := .funcString(, false), .funcString(, false)* = .sprintf("(missing method %s)\n\t\thave %s\n\t\twant %s", .Name(), , )case :* = .sprintf("(unexported method %s)", .Name())case :, := .funcString(, false), .funcString(, false)if == {// Don't report "want Foo, have Foo".// Add package information to disambiguate (go.dev/issue/54258)., = .funcString(, true), .funcString(, true)}if == {// We still have "want Foo, have Foo".// This is most likely due to different type parameters with// the same name appearing in the instantiated signatures// (go.dev/issue/61685).// Rather than reporting this misleading error cause, for now// just point out that the method signature is incorrect.// TODO(gri) should find a good way to report the root cause* = .sprintf("(wrong type for method %s)", .Name())break}* = .sprintf("(wrong type for method %s)\n\t\thave %s\n\t\twant %s", .Name(), , )case :* = .sprintf("(ambiguous selector %s.%s)", , .Name())case :* = .sprintf("(method %s has pointer receiver)", .Name())case :* = .sprintf("(%s.%s is a field, not a method)", , .Name())default:panic("unreachable")}}return , == || ==}// hasAllMethods is similar to checkMissingMethod but instead reports whether all methods are present.// If V is not a valid type, or if it is a struct containing embedded fields with invalid types, the// result is true because it is not possible to say with certainty whether a method is missing or not// (an embedded field may have the method in question).// If the result is false and cause is not nil, *cause describes the error.// Use hasAllMethods to avoid follow-on errors due to incorrect types.func ( *Checker) (, Type, bool, func(, Type) bool, *string) bool {if !isValid() {return true // we don't know anything about V, assume it implements T}, := .missingMethod(, , , , )return == nil || hasInvalidEmbeddedFields(, nil)}// hasInvalidEmbeddedFields reports whether T is a struct (or a pointer to a struct) that contains// (directly or indirectly) embedded fields with invalid types.func hasInvalidEmbeddedFields( Type, map[*Struct]bool) bool {if , := under(derefStructPtr()).(*Struct); != nil && ![] {if == nil {= make(map[*Struct]bool)}[] = truefor , := range .fields {if .embedded && (!isValid(.typ) || (.typ, )) {return true}}}return false}func isInterfacePtr( Type) bool {, := under().(*Pointer)return != nil && IsInterface(.base)}// check may be nil.func ( *Checker) ( Type) string {assert(isInterfacePtr())if , := under().(*Pointer); isTypeParam(.base) {return .sprintf("type %s is pointer to type parameter, not type parameter", )}return .sprintf("type %s is pointer to interface, not interface", )}// funcString returns a string of the form name + signature for f.// check may be nil.func ( *Checker) ( *Func, bool) string {:= bytes.NewBufferString(.name)var Qualifierif != nil && ! {= .qualifier}:= newTypeWriter(, ).pkgInfo =.paramNames = false.signature(.typ.(*Signature))return .String()}// assertableTo reports whether a value of type V can be asserted to have type T.// The receiver may be nil if assertableTo is invoked through an exported API call// (such as AssertableTo), i.e., when all methods have been type-checked.// The underlying type of V must be an interface.// If the result is false and cause is not nil, *cause describes the error.// TODO(gri) replace calls to this function with calls to newAssertableTo.func ( *Checker) (, Type, *string) bool {// no static check is required if T is an interface// spec: "If T is an interface type, x.(T) asserts that the// dynamic type of x implements the interface T."if IsInterface() {return true}// TODO(gri) fix this for generalized interfacesreturn .hasAllMethods(, , false, Identical, )}// newAssertableTo reports whether a value of type V can be asserted to have type T.// It also implements behavior for interfaces that currently are only permitted// in constraint position (we have not yet defined that behavior in the spec).// The underlying type of V must be an interface.// If the result is false and cause is not nil, *cause is set to the error cause.func ( *Checker) (, Type, *string) bool {// no static check is required if T is an interface// spec: "If T is an interface type, x.(T) asserts that the// dynamic type of x implements the interface T."if IsInterface() {return true}return .implements(, , false, )}// deref dereferences typ if it is a *Pointer (but not a *Named type// with an underlying pointer type!) and returns its base and true.// Otherwise it returns (typ, false).func deref( Type) (Type, bool) {if , := Unalias().(*Pointer); != nil {// p.base should never be nil, but be conservativeif .base == nil {if debug {panic("pointer with nil base type (possibly due to an invalid cyclic declaration)")}return Typ[Invalid], true}return .base, true}return , false}// derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a// (named or unnamed) struct and returns its base. Otherwise it returns typ.func derefStructPtr( Type) Type {if , := under().(*Pointer); != nil {if , := under(.base).(*Struct); {return .base}}return}// concat returns the result of concatenating list and i.// The result does not share its underlying array with list.func concat( []int, int) []int {var []int= append(, ...)return append(, )}// fieldIndex returns the index for the field with matching package and name, or a value < 0.// See Object.sameId for the meaning of foldCase.func fieldIndex( []*Var, *Package, string, bool) int {if != "_" {for , := range {if .sameId(, , ) {return}}}return -1}// methodIndex returns the index of and method with matching package and name, or (-1, nil).// See Object.sameId for the meaning of foldCase.func methodIndex( []*Func, *Package, string, bool) (int, *Func) {if != "_" {for , := range {if .sameId(, , ) {return ,}}}return -1, nil}
![]() |
The pages are generated with Golds v0.7.9-preview. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |