]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/cmd/compile/internal/types2/signature.go
go/types, types2: introduce _Alias type node
[gostls13.git] / src / cmd / compile / internal / types2 / signature.go
index 48b11b289cdfb1fb9cecc4dc06efed180e41395a..f876b16c8f6b4c47a3c0195b0a80d32c7e5084c3 100644 (file)
@@ -7,6 +7,7 @@ package types2
 import (
        "cmd/compile/internal/syntax"
        "fmt"
+       . "internal/types/errors"
 )
 
 // ----------------------------------------------------------------------------
@@ -19,30 +20,46 @@ type Signature struct {
        // 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  *TypeParams // receiver type parameters from left to right, or nil
-       tparams  *TypeParams // type parameters from left to right, or nil
-       scope    *Scope      // function scope, present for package-local signatures
-       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)
+       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.
-func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
+// 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 NewSignatureType(recv *Var, recvTypeParams, typeParams []*TypeParam, params, results *Tuple, variadic bool) *Signature {
        if variadic {
                n := params.Len()
                if n == 0 {
                        panic("variadic function must have at least one parameter")
                }
-               if _, ok := params.At(n - 1).typ.(*Slice); !ok {
-                       panic("variadic parameter must be of unnamed slice type")
+               core := coreString(params.At(n - 1).typ)
+               if _, ok := core.(*Slice); !ok && !isString(core) {
+                       panic(fmt.Sprintf("got %s, want variadic parameter with unnamed slice type or string as core type", core.String()))
                }
        }
-       return &Signature{recv: recv, params: params, results: results, variadic: variadic}
+       sig := &Signature{recv: recv, params: params, results: results, variadic: variadic}
+       if len(recvTypeParams) != 0 {
+               if recv == nil {
+                       panic("function with receiver type parameters must have a receiver")
+               }
+               sig.rparams = bindTParams(recvTypeParams)
+       }
+       if len(typeParams) != 0 {
+               if recv != nil {
+                       panic("function with type parameters cannot have a receiver")
+               }
+               sig.tparams = bindTParams(typeParams)
+       }
+       return sig
 }
 
 // Recv returns the receiver of signature s (if a method), or nil if a
@@ -53,17 +70,14 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
 // contain methods whose receiver type is a different interface.
 func (s *Signature) Recv() *Var { return s.recv }
 
-// TParams returns the type parameters of signature s, or nil.
-func (s *Signature) TParams() *TypeParams { return s.tparams }
-
-// SetTParams sets the type parameters of signature s.
-func (s *Signature) SetTParams(tparams []*TypeName) { s.tparams = bindTParams(tparams) }
+// TypeParams returns the type parameters of signature s, or nil.
+func (s *Signature) TypeParams() *TypeParamList { return s.tparams }
 
-// RParams returns the receiver type parameters of signature s, or nil.
-func (s *Signature) RParams() *TypeParams { return s.rparams }
+// SetTypeParams sets the type parameters of signature s.
+func (s *Signature) SetTypeParams(tparams []*TypeParam) { s.tparams = bindTParams(tparams) }
 
-// SetRParams sets the receiver type params of signature s.
-func (s *Signature) SetRParams(rparams []*TypeName) { s.rparams = bindTParams(rparams) }
+// RecvTypeParams returns the receiver type parameters of signature s, or nil.
+func (s *Signature) RecvTypeParams() *TypeParamList { return s.rparams }
 
 // Params returns the parameters of signature s, or nil.
 func (s *Signature) Params() *Tuple { return s.params }
@@ -80,9 +94,6 @@ func (s *Signature) String() string   { return TypeString(s, nil) }
 // ----------------------------------------------------------------------------
 // Implementation
 
-// Disabled by default, but enabled when running tests (via types_test.go).
-var acceptMethodTypeParams bool
-
 // funcType type-checks a function or method type.
 func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []*syntax.Field, ftyp *syntax.FuncType) {
        check.openScope(ftyp, "function")
@@ -91,84 +102,69 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
        sig.scope = check.scope
        defer check.closeScope()
 
-       var recvTyp syntax.Expr // rewritten receiver type; valid if != nil
        if recvPar != nil {
                // 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
                _, rname, rparams := check.unpackRecv(recvPar.Type, true)
                if len(rparams) > 0 {
-                       // Blank identifiers don't get declared and regular type-checking of the instantiated
-                       // parameterized receiver type expression fails in Checker.collectParams of receiver.
-                       // Identify blank type parameters and substitute each with a unique new identifier named
-                       // "n_" (where n is the parameter index) and which cannot conflict with any user-defined
-                       // name.
-                       var smap map[*syntax.Name]*syntax.Name // substitution map from "_" to "!n" identifiers
+                       tparams := make([]*TypeParam, len(rparams))
+                       for i, rparam := range rparams {
+                               tparams[i] = check.declareTypeParam(rparam)
+                       }
+                       sig.rparams = bindTParams(tparams)
+                       // 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 i, p := range rparams {
                                if p.Value == "_" {
-                                       new := *p
-                                       new.Value = fmt.Sprintf("%d_", i)
-                                       rparams[i] = &new // use n_ identifier instead of _ so it can be looked up
-                                       if smap == nil {
-                                               smap = make(map[*syntax.Name]*syntax.Name)
+                                       if check.recvTParamMap == nil {
+                                               check.recvTParamMap = make(map[*syntax.Name]*TypeParam)
                                        }
-                                       smap[p] = &new
+                                       check.recvTParamMap[p] = tparams[i]
                                }
                        }
-                       if smap != nil {
-                               // blank identifiers were found => use rewritten receiver type
-                               recvTyp = isubst(recvPar.Type, smap)
-                       }
-                       rlist := make([]*TypeName, len(rparams))
-                       for i, rparam := range rparams {
-                               rlist[i] = check.declareTypeParam(rparam)
-                       }
-                       sig.rparams = bindTParams(rlist)
                        // determine receiver type to get its type parameters
                        // and the respective type parameter bounds
-                       var recvTParams []*TypeName
+                       var recvTParams []*TypeParam
                        if rname != 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 recv := asNamed(check.genericType(rname, false)); recv != nil {
-                                       recvTParams = recv.TParams().list()
+                               if recv := asNamed(check.genericType(rname, nil)); recv != nil {
+                                       recvTParams = recv.TypeParams().list()
                                }
                        }
                        // provide type parameter bounds
-                       // - only do this if we have the right number (otherwise an error is reported elsewhere)
-                       if sig.RParams().Len() == len(recvTParams) {
-                               // We have a list of *TypeNames but we need a list of Types.
-                               list := make([]Type, sig.RParams().Len())
-                               for i, t := range sig.RParams().list() {
-                                       list[i] = t.typ
-                               }
-                               smap := makeSubstMap(recvTParams, list)
-                               for i, tname := range sig.RParams().list() {
-                                       bound := recvTParams[i].typ.(*TypeParam).bound
-                                       // bound is (possibly) parameterized in the context of the
-                                       // receiver type declaration. Substitute parameters for the
-                                       // current context.
-                                       // TODO(gri) should we assume now that bounds always exist?
-                                       //           (no bound == empty interface)
-                                       if bound != nil {
-                                               bound = check.subst(tname.pos, bound, smap)
-                                               tname.typ.(*TypeParam).bound = bound
-                                       }
+                       if len(tparams) == len(recvTParams) {
+                               smap := makeRenameMap(recvTParams, tparams)
+                               for i, tpar := range tparams {
+                                       recvTPar := recvTParams[i]
+                                       check.mono.recordCanon(tpar, recvTPar)
+                                       // recvTPar.bound is (possibly) parameterized in the context of the
+                                       // receiver type declaration. Substitute parameters for the current
+                                       // context.
+                                       tpar.bound = check.subst(tpar.obj.pos, recvTPar.bound, smap, nil, check.context())
                                }
+                       } else if len(tparams) < len(recvTParams) {
+                               // 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
+                               got := measure(len(tparams), "type parameter")
+                               check.errorf(recvPar, BadRecv, "got %s, but receiver base type declares %d", got, len(recvTParams))
                        }
                }
        }
 
        if tparams != nil {
-               sig.tparams = check.collectTypeParams(tparams)
-               // Always type-check method type parameters but complain if they are not enabled.
-               // (A separate check is needed when type-checking interface method signatures because
-               // they don't have a receiver specification.)
-               if recvPar != nil && !acceptMethodTypeParams {
-                       check.error(ftyp, "methods cannot have type parameters")
-               }
+               // The parser will complain about invalid type parameters for methods.
+               check.collectTypeParams(&sig.tparams, tparams)
        }
 
        // Value (non-type) parameters' scope starts in the function body. Use a temporary scope for their
@@ -177,12 +173,13 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
        scope := NewScope(check.scope, nopos, nopos, "function body (temp. scope)")
        var recvList []*Var // TODO(gri) remove the need for making a list here
        if recvPar != nil {
-               recvList, _ = check.collectParams(scope, []*syntax.Field{recvPar}, recvTyp, false) // use rewritten receiver type, if any
+               recvList, _ = check.collectParams(scope, []*syntax.Field{recvPar}, false) // use rewritten receiver type, if any
        }
-       params, variadic := check.collectParams(scope, ftyp.ParamList, nil, true)
-       results, _ := check.collectParams(scope, ftyp.ResultList, nil, false)
+       params, variadic := check.collectParams(scope, ftyp.ParamList, true)
+       results, _ := check.collectParams(scope, ftyp.ResultList, false)
        scope.Squash(func(obj, alt Object) {
                var err error_
+               err.code = DuplicateDecl
                err.errorf(obj, "%s redeclared in this block", obj.Name())
                err.recordAltDecl(alt)
                check.report(&err)
@@ -199,65 +196,60 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
                        recv = NewParam(nopos, nil, "", Typ[Invalid]) // ignore recv below
                default:
                        // more than one receiver
-                       check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver")
+                       check.error(recvList[len(recvList)-1].Pos(), InvalidRecv, "method must have exactly one receiver")
                        fallthrough // continue with first receiver
                case 1:
                        recv = recvList[0]
                }
+               sig.recv = recv
 
-               // TODO(gri) We should delay rtyp expansion to when we actually need the
-               //           receiver; thus all checks here should be delayed to later.
-               rtyp, _ := deref(recv.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 rtyp != Typ[Invalid] {
-                       var err string
-                       switch T := rtyp.(type) {
+               // 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).
+               check.later(func() {
+                       // spec: "The receiver type must be of the form T or *T where T is a type name."
+                       rtyp, _ := deref(recv.typ)
+                       atyp := _Unalias(rtyp)
+                       if !isValid(atyp) {
+                               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 := atyp.(type) {
                        case *Named:
-                               T.expand()
-                               // 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."
+                               // The receiver type may be an instantiated type referred to
+                               // by an alias (which cannot have receiver parameters for now).
+                               if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
+                                       check.errorf(recv, InvalidRecv, "cannot define new methods on instantiated type %s", rtyp)
+                                       break
+                               }
                                if T.obj.pkg != check.pkg {
-                                       err = "type not defined in this package"
-                                       if check.conf.CompilerErrorMessages {
-                                               check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
-                                               err = ""
+                                       check.errorf(recv, InvalidRecv, "cannot define new methods on non-local type %s", rtyp)
+                                       break
+                               }
+                               var cause string
+                               switch u := T.under().(type) {
+                               case *Basic:
+                                       // unsafe.Pointer is treated like a regular pointer
+                                       if u.kind == UnsafePointer {
+                                               cause = "unsafe.Pointer"
                                        }
-                               } 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.
-                                       underIs(T, func(u Type) bool {
-                                               switch u := u.(type) {
-                                               case *Basic:
-                                                       // unsafe.Pointer is treated like a regular pointer
-                                                       if u.kind == UnsafePointer {
-                                                               err = "unsafe.Pointer"
-                                                               return false
-                                                       }
-                                               case *Pointer, *Interface:
-                                                       err = "pointer or interface type"
-                                                       return false
-                                               }
-                                               return true
-                                       })
+                               case *Pointer, *Interface:
+                                       cause = "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.
+                                       unreachable()
                                }
-                       case *Basic:
-                               err = "basic or unnamed type"
-                               if check.conf.CompilerErrorMessages {
-                                       check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
-                                       err = ""
+                               if cause != "" {
+                                       check.errorf(recv, InvalidRecv, "invalid receiver type %s (%s)", rtyp, cause)
                                }
+                       case *Basic:
+                               check.errorf(recv, InvalidRecv, "cannot define new methods on non-local type %s", rtyp)
                        default:
-                               check.errorf(recv.pos, "invalid receiver type %s", recv.typ)
-                       }
-                       if err != "" {
-                               check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
-                               // ok to continue
+                               check.errorf(recv, InvalidRecv, "invalid receiver type %s", recv.typ)
                        }
-               }
-               sig.recv = recv
+               }).describef(recv, "validate receiver %s", recv)
        }
 
        sig.params = NewTuple(params...)
@@ -266,8 +258,8 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
 }
 
 // collectParams declares the parameters of list in scope and returns the corresponding
-// variable list. If type0 != nil, it is used instead of the first type in list.
-func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 syntax.Expr, variadicOk bool) (params []*Var, variadic bool) {
+// variable list.
+func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, variadicOk bool) (params []*Var, variadic bool) {
        if list == nil {
                return
        }
@@ -281,15 +273,12 @@ func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 sy
                // type-check type of grouped fields only once
                if ftype != prev {
                        prev = ftype
-                       if i == 0 && type0 != nil {
-                               ftype = type0
-                       }
                        if t, _ := ftype.(*syntax.DotsType); t != nil {
                                ftype = t.Elem
                                if variadicOk && i == len(list)-1 {
                                        variadic = true
                                } else {
-                                       check.softErrorf(t, "can only use ... with final parameter in list")
+                                       check.softErrorf(t, MisplacedDotDotDot, "can only use ... with final parameter in list")
                                        // ignore ... and continue
                                }
                        }
@@ -301,7 +290,7 @@ func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 sy
                        // named parameter
                        name := field.Name.Value
                        if name == "" {
-                               check.error(field.Name, invalidAST+"anonymous parameter")
+                               check.error(field.Name, InvalidSyntaxTree, "anonymous parameter")
                                // ok to continue
                        }
                        par := NewParam(field.Name.Pos(), check.pkg, name, typ)
@@ -318,7 +307,7 @@ func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 sy
        }
 
        if named && anonymous {
-               check.error(list[0], invalidAST+"list contains both named and anonymous parameters")
+               check.error(list[0], InvalidSyntaxTree, "list contains both named and anonymous parameters")
                // ok to continue
        }
 
@@ -333,61 +322,3 @@ func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 sy
 
        return
 }
-
-// isubst returns an x with identifiers substituted per the substitution map smap.
-// isubst only handles the case of (valid) method receiver type expressions correctly.
-func isubst(x syntax.Expr, smap map[*syntax.Name]*syntax.Name) syntax.Expr {
-       switch n := x.(type) {
-       case *syntax.Name:
-               if alt := smap[n]; alt != nil {
-                       return alt
-               }
-       // case *syntax.StarExpr:
-       //      X := isubst(n.X, smap)
-       //      if X != n.X {
-       //              new := *n
-       //              new.X = X
-       //              return &new
-       //      }
-       case *syntax.Operation:
-               if n.Op == syntax.Mul && n.Y == nil {
-                       X := isubst(n.X, smap)
-                       if X != n.X {
-                               new := *n
-                               new.X = X
-                               return &new
-                       }
-               }
-       case *syntax.IndexExpr:
-               Index := isubst(n.Index, smap)
-               if Index != n.Index {
-                       new := *n
-                       new.Index = Index
-                       return &new
-               }
-       case *syntax.ListExpr:
-               var elems []syntax.Expr
-               for i, elem := range n.ElemList {
-                       new := isubst(elem, smap)
-                       if new != elem {
-                               if elems == nil {
-                                       elems = make([]syntax.Expr, len(n.ElemList))
-                                       copy(elems, n.ElemList)
-                               }
-                               elems[i] = new
-                       }
-               }
-               if elems != nil {
-                       new := *n
-                       new.ElemList = elems
-                       return &new
-               }
-       case *syntax.ParenExpr:
-               return isubst(n.X, smap) // no need to keep parentheses
-       default:
-               // Other receiver type expressions are invalid.
-               // It's fine to ignore those here as they will
-               // be checked elsewhere.
-       }
-       return x
-}