// 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 nil tparams *TypeParamList// type parameters from left to right, or nil scope *Scope// function scope for package-local and non-instantiated signatures; nil otherwise recv *Var// nil if not a method params *Tuple// (incoming) parameters from left to right; or nil results *Tuple// (outgoing) results from left to right; or nil variadic bool// 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's core type must be of unnamed slice or bytestring 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") } := coreString(.At( - 1).typ)if , := .(*Slice); ! && !isString() {panic(fmt.Sprintf("got %s, want variadic parameter with unnamed slice type or string as core type", .String())) } } := &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 {// The scope of the type parameter T in "func (r T[T]) f()" // starts after f, not at "r"; see #52038. := .Params.Pos() := .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 := asNamed(.genericType(, nil)); != 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, .context()) } } 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 go.dev/issue/51339, go.dev/issue/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 { .error(.TypeParams, InvalidMethodTypeParams, "methods cannot have type parameters") } }// Use a temporary scope for all parameter declarations and then // squash that scope into the parent scope (and report any // redeclarations at that time). // // TODO(adonovan): now that each declaration has the correct // scopePos, there should be no need for scope squashing. // Audit to ensure all lookups honor scopePos and simplify. := NewScope(.scope, nopos, nopos, "function body (temp. scope)") := .End() // all parameters' scopes start after the signature , := .collectParams(, , false, ) , := .collectParams(, .Params, true, ) , := .collectParams(, .Results, false, ) .squash(func(, Object) { := .newError(DuplicateDecl) .addf(, "%s redeclared in this block", .Name()) .addAltDecl() .report() })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(nopos, nil, "", Typ[Invalid]) // ignore recv belowdefault:// more than one receiver .error([len()-1], InvalidRecv, "method has multiple receivers")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 go.dev/issue/51232, go.dev/issue/51233). .later(func() {// spec: "The receiver type must be of the form T or *T where T is a type name." , := deref(.typ) := Unalias()if !isValid() {return// error was reported before }// 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."switch T := .(type) {case *Named:// 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 new methods on instantiated type %s", )break }if .obj.pkg != .pkg { .errorf(, InvalidRecv, "cannot define new methods on non-local type %s", )break }varstringswitch u := .under().(type) {case *Basic:// unsafe.Pointer is treated like a regular pointerif .kind == UnsafePointer { = "unsafe.Pointer" }case *Pointer, *Interface: = "pointer or interface type"case *TypeParam:// The underlying type of a receiver base type cannot be a // type parameter: "type T[P any] P" is not a valid declaration.panic("unreachable") }if != "" { .errorf(, InvalidRecv, "invalid receiver type %s (%s)", , ) }case *Basic: .errorf(, InvalidRecv, "cannot define new methods on non-local type %s", )default: .errorf(, InvalidRecv, "invalid receiver type %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, token.Pos) ( []*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 == "" { .error(, InvalidSyntaxTree, "anonymous parameter")// ok to continue } := NewParam(.Pos(), .pkg, .Name, ) .declare(, , , ) = append(, ) } = true } else {// anonymous parameter := NewParam(.Pos(), .pkg, "", ) .recordImplicit(, ) = append(, ) = true } }if && { .error(, InvalidSyntaxTree, "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.7.0-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.