// Copyright 2021 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.package typesimport ()// ----------------------------------------------------------------------------// API// A Signature represents a (non-builtin) function or method type.// The receiver is ignored when comparing signatures for identity.typeSignaturestruct {// We need to keep the scope in Signature (rather than passing it around // and store it in the Func Object) because when type-checking a function // literal we call the general type checker which returns a general Type. // We then unpack the *Signature and use the scope for the literal body.rparams *TypeParamList// receiver type parameters from left to right, or niltparams *TypeParamList// type parameters from left to right, or nilscope *Scope// function scope for package-local and non-instantiated signatures; nil otherwiserecv *Var// nil if not a methodparams *Tuple// (incoming) parameters from left to right; or nilresults *Tuple// (outgoing) results from left to right; or nilvariadicbool// true if the last parameter's type is of the form ...T (or string, for append built-in only)}// NewSignature returns a new function type for the given receiver, parameters,// and results, either of which may be nil. If variadic is set, the function// is variadic, it must have at least one parameter, and the last parameter// must be of unnamed slice type.//// Deprecated: Use NewSignatureType instead which allows for type parameters.func ( *Var, , *Tuple, bool) *Signature {returnNewSignatureType(, nil, nil, , , )}// NewSignatureType creates a new function type for the given receiver,// receiver type parameters, type parameters, parameters, and results. If// variadic is set, params must hold at least one parameter and the last// parameter must be of unnamed slice type. If recv is non-nil, typeParams must// be empty. If recvTypeParams is non-empty, recv must be non-nil.func ( *Var, , []*TypeParam, , *Tuple, bool) *Signature {if { := .Len()if == 0 {panic("variadic function must have at least one parameter") }if , := .At( - 1).typ.(*Slice); ! {panic("variadic parameter must be of unnamed slice type") } } := &Signature{recv: , params: , results: , variadic: }iflen() != 0 {if == nil {panic("function with receiver type parameters must have a receiver") } .rparams = bindTParams() }iflen() != 0 {if != nil {panic("function with type parameters cannot have a receiver") } .tparams = bindTParams() }return}// Recv returns the receiver of signature s (if a method), or nil if a// function. It is ignored when comparing signatures for identity.//// For an abstract method, Recv returns the enclosing interface either// as a *Named or an *Interface. Due to embedding, an interface may// contain methods whose receiver type is a different interface.func ( *Signature) () *Var { return .recv }// TypeParams returns the type parameters of signature s, or nil.func ( *Signature) () *TypeParamList { return .tparams }// RecvTypeParams returns the receiver type parameters of signature s, or nil.func ( *Signature) () *TypeParamList { return .rparams }// Params returns the parameters of signature s, or nil.func ( *Signature) () *Tuple { return .params }// Results returns the results of signature s, or nil.func ( *Signature) () *Tuple { return .results }// Variadic reports whether the signature s is variadic.func ( *Signature) () bool { return .variadic }func ( *Signature) () Type { return }func ( *Signature) () string { returnTypeString(, nil) }// ----------------------------------------------------------------------------// Implementation// funcType type-checks a function or method type.func ( *Checker) ( *Signature, *ast.FieldList, *ast.FuncType) { .openScope(, "function") .scope.isFunc = true .recordScope(, .scope) .scope = .scopedefer .closeScope()if != nil && len(.List) > 0 {// collect generic receiver type parameters, if any // - a receiver type parameter is like any other type parameter, except that it is declared implicitly // - the receiver specification acts as local declaration for its type parameters, which may be blank , , := .unpackRecv(.List[0].Type, true)iflen() > 0 { := .declareTypeParams(nil, ) .rparams = bindTParams()// Blank identifiers don't get declared, so naive type-checking of the // receiver type expression would fail in Checker.collectParams below, // when Checker.ident cannot resolve the _ to a type. // // Checker.recvTParamMap maps these blank identifiers to their type parameter // types, so that they may be resolved in Checker.ident when they fail // lookup in the scope.for , := range {if .Name == "_" {if .recvTParamMap == nil { .recvTParamMap = make(map[*ast.Ident]*TypeParam) } .recvTParamMap[] = [] } }// determine receiver type to get its type parameters // and the respective type parameter boundsvar []*TypeParamif != nil {// recv should be a Named type (otherwise an error is reported elsewhere) // Also: Don't report an error via genericType since it will be reported // again when we type-check the signature. // TODO(gri) maybe the receiver should be marked as invalid instead?if , := .genericType(, nil).(*Named); != nil { = .TypeParams().list() } }// provide type parameter boundsiflen() == len() { := makeRenameMap(, )for , := range { := [] .mono.recordCanon(, )// recvTPar.bound is (possibly) parameterized in the context of the // receiver type declaration. Substitute parameters for the current // context. .bound = .subst(.obj.pos, .bound, , nil) } } elseiflen() < len() {// Reporting an error here is a stop-gap measure to avoid crashes in the // compiler when a type parameter/argument cannot be inferred later. It // may lead to follow-on errors (see issues #51339, #51343). // TODO(gri) find a better solution := measure(len(), "type parameter") .errorf(, _BadRecv, "got %s, but receiver base type declares %d", , len()) } } }if .TypeParams != nil { .collectTypeParams(&.tparams, .TypeParams)// Always type-check method type parameters but complain that they are not allowed. // (A separate check is needed when type-checking interface method signatures because // they don't have a receiver specification.)if != nil { .errorf(.TypeParams, _InvalidMethodTypeParams, "methods cannot have type parameters") } }// Value (non-type) parameters' scope starts in the function body. Use a temporary scope for their // declarations and then squash that scope into the parent scope (and report any redeclarations at // that time). := NewScope(.scope, token.NoPos, token.NoPos, "function body (temp. scope)") , := .collectParams(, , false) , := .collectParams(, .Params, true) , := .collectParams(, .Results, false) .squash(func(, Object) { .errorf(, _DuplicateDecl, "%s redeclared in this block", .Name()) .reportAltDecl() })if != nil {// recv parameter list present (may be empty) // spec: "The receiver is specified via an extra parameter section preceding the // method name. That parameter section must declare a single parameter, the receiver."var *Varswitchlen() {case0:// error reported by resolver = NewParam(token.NoPos, nil, "", Typ[Invalid]) // ignore recv belowdefault:// more than one receiver .error([len()-1], _InvalidRecv, "method must have exactly one receiver")fallthrough// continue with first receivercase1: = [0] } .recv = // Delay validation of receiver type as it may cause premature expansion // of types the receiver type is dependent on (see issues #51232, #51233). .later(func() { , := deref(.typ)// spec: "The receiver type must be of the form T or *T where T is a type name." // (ignore invalid types - error was reported before)if != Typ[Invalid] {varstringswitch T := .(type) {case *Named: .resolve(.bestContext(nil))// The receiver type may be an instantiated type referred to // by an alias (which cannot have receiver parameters for now).if .TypeArgs() != nil && .RecvTypeParams() == nil { .errorf(, _InvalidRecv, "cannot define methods on instantiated type %s", .typ)break }// 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."if .obj.pkg != .pkg { = "type not defined in this package"ifcompilerErrorMessages { .errorf(, _InvalidRecv, "cannot define new methods on non-local type %s", .typ) = "" } } else {// The underlying type of a receiver base type can be a type parameter; // e.g. for methods with a generic receiver T[P] with type T[P any] P. // TODO(gri) Such declarations are currently disallowed. // Revisit the need for underIs.underIs(, func( Type) bool {switch u := .(type) {case *Basic:// unsafe.Pointer is treated like a regular pointerif .kind == UnsafePointer { = "unsafe.Pointer"returnfalse }case *Pointer, *Interface: = "pointer or interface type"returnfalse }returntrue }) }case *Basic: = "basic or unnamed type"ifcompilerErrorMessages { .errorf(, _InvalidRecv, "cannot define new methods on non-local type %s", .typ) = "" }default: .errorf(, _InvalidRecv, "invalid receiver type %s", .typ) }if != "" { .errorf(, _InvalidRecv, "invalid receiver type %s (%s)", .typ, ) } } }).describef(, "validate receiver %s", ) } .params = NewTuple(...) .results = NewTuple(...) .variadic = }// collectParams declares the parameters of list in scope and returns the corresponding// variable list.func ( *Checker) ( *Scope, *ast.FieldList, bool) ( []*Var, bool) {if == nil {return }var , boolfor , := range .List { := .Typeif , := .(*ast.Ellipsis); != nil { = .Eltif && == len(.List)-1 && len(.Names) <= 1 { = true } else { .softErrorf(, _MisplacedDotDotDot, "can only use ... with final parameter in list")// ignore ... and continue } } := .varType()// The parser ensures that f.Tag is nil and we don't // care if a constructed AST contains a non-nil tag.iflen(.Names) > 0 {// named parameterfor , := range .Names {if .Name == "" { .invalidAST(, "anonymous parameter")// ok to continue } := NewParam(.Pos(), .pkg, .Name, ) .declare(, , , .pos) = append(, ) } = true } else {// anonymous parameter := NewParam(.Pos(), .pkg, "", ) .recordImplicit(, ) = append(, ) = true } }if && { .invalidAST(, "list contains both named and anonymous parameters")// ok to continue }// For a variadic function, change the last parameter's type from T to []T. // Since we type-checked T rather than ...T, we also need to retro-actively // record the type for ...T.if { := [len()-1] .typ = &Slice{elem: .typ} .recordTypeAndValue(.List[len(.List)-1].Type, typexpr, .typ, nil) }return}
The pages are generated with Goldsv0.4.9. (GOOS=linux GOARCH=amd64)