]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/types2/signature.go
[dev.typeparams] all: merge master (f22ec51) into dev.typeparams
[gostls13.git] / src / cmd / compile / internal / types2 / signature.go
1 // Copyright 2021 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package types2
6
7 import (
8         "cmd/compile/internal/syntax"
9         "fmt"
10 )
11
12 // Disabled by default, but enabled when running tests (via types_test.go).
13 var acceptMethodTypeParams bool
14
15 // funcType type-checks a function or method type.
16 func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []*syntax.Field, ftyp *syntax.FuncType) {
17         check.openScope(ftyp, "function")
18         check.scope.isFunc = true
19         check.recordScope(ftyp, check.scope)
20         sig.scope = check.scope
21         defer check.closeScope()
22
23         var recvTyp syntax.Expr // rewritten receiver type; valid if != nil
24         if recvPar != nil {
25                 // collect generic receiver type parameters, if any
26                 // - a receiver type parameter is like any other type parameter, except that it is declared implicitly
27                 // - the receiver specification acts as local declaration for its type parameters, which may be blank
28                 _, rname, rparams := check.unpackRecv(recvPar.Type, true)
29                 if len(rparams) > 0 {
30                         // Blank identifiers don't get declared and regular type-checking of the instantiated
31                         // parameterized receiver type expression fails in Checker.collectParams of receiver.
32                         // Identify blank type parameters and substitute each with a unique new identifier named
33                         // "n_" (where n is the parameter index) and which cannot conflict with any user-defined
34                         // name.
35                         var smap map[*syntax.Name]*syntax.Name // substitution map from "_" to "!n" identifiers
36                         for i, p := range rparams {
37                                 if p.Value == "_" {
38                                         new := *p
39                                         new.Value = fmt.Sprintf("%d_", i)
40                                         rparams[i] = &new // use n_ identifier instead of _ so it can be looked up
41                                         if smap == nil {
42                                                 smap = make(map[*syntax.Name]*syntax.Name)
43                                         }
44                                         smap[p] = &new
45                                 }
46                         }
47                         if smap != nil {
48                                 // blank identifiers were found => use rewritten receiver type
49                                 recvTyp = isubst(recvPar.Type, smap)
50                         }
51                         // TODO(gri) rework declareTypeParams
52                         sig.rparams = nil
53                         for _, rparam := range rparams {
54                                 sig.rparams = check.declareTypeParam(sig.rparams, rparam)
55                         }
56                         // determine receiver type to get its type parameters
57                         // and the respective type parameter bounds
58                         var recvTParams []*TypeName
59                         if rname != nil {
60                                 // recv should be a Named type (otherwise an error is reported elsewhere)
61                                 // Also: Don't report an error via genericType since it will be reported
62                                 //       again when we type-check the signature.
63                                 // TODO(gri) maybe the receiver should be marked as invalid instead?
64                                 if recv := asNamed(check.genericType(rname, false)); recv != nil {
65                                         recvTParams = recv.tparams
66                                 }
67                         }
68                         // provide type parameter bounds
69                         // - only do this if we have the right number (otherwise an error is reported elsewhere)
70                         if len(sig.rparams) == len(recvTParams) {
71                                 // We have a list of *TypeNames but we need a list of Types.
72                                 list := make([]Type, len(sig.rparams))
73                                 for i, t := range sig.rparams {
74                                         list[i] = t.typ
75                                 }
76                                 smap := makeSubstMap(recvTParams, list)
77                                 for i, tname := range sig.rparams {
78                                         bound := recvTParams[i].typ.(*TypeParam).bound
79                                         // bound is (possibly) parameterized in the context of the
80                                         // receiver type declaration. Substitute parameters for the
81                                         // current context.
82                                         // TODO(gri) should we assume now that bounds always exist?
83                                         //           (no bound == empty interface)
84                                         if bound != nil {
85                                                 bound = check.subst(tname.pos, bound, smap)
86                                                 tname.typ.(*TypeParam).bound = bound
87                                         }
88                                 }
89                         }
90                 }
91         }
92
93         if tparams != nil {
94                 sig.tparams = check.collectTypeParams(tparams)
95                 // Always type-check method type parameters but complain if they are not enabled.
96                 // (A separate check is needed when type-checking interface method signatures because
97                 // they don't have a receiver specification.)
98                 if recvPar != nil && !acceptMethodTypeParams {
99                         check.error(ftyp, "methods cannot have type parameters")
100                 }
101         }
102
103         // Value (non-type) parameters' scope starts in the function body. Use a temporary scope for their
104         // declarations and then squash that scope into the parent scope (and report any redeclarations at
105         // that time).
106         scope := NewScope(check.scope, nopos, nopos, "function body (temp. scope)")
107         var recvList []*Var // TODO(gri) remove the need for making a list here
108         if recvPar != nil {
109                 recvList, _ = check.collectParams(scope, []*syntax.Field{recvPar}, recvTyp, false) // use rewritten receiver type, if any
110         }
111         params, variadic := check.collectParams(scope, ftyp.ParamList, nil, true)
112         results, _ := check.collectParams(scope, ftyp.ResultList, nil, false)
113         scope.Squash(func(obj, alt Object) {
114                 var err error_
115                 err.errorf(obj, "%s redeclared in this block", obj.Name())
116                 err.recordAltDecl(alt)
117                 check.report(&err)
118         })
119
120         if recvPar != nil {
121                 // recv parameter list present (may be empty)
122                 // spec: "The receiver is specified via an extra parameter section preceding the
123                 // method name. That parameter section must declare a single parameter, the receiver."
124                 var recv *Var
125                 switch len(recvList) {
126                 case 0:
127                         // error reported by resolver
128                         recv = NewParam(nopos, nil, "", Typ[Invalid]) // ignore recv below
129                 default:
130                         // more than one receiver
131                         check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver")
132                         fallthrough // continue with first receiver
133                 case 1:
134                         recv = recvList[0]
135                 }
136
137                 // TODO(gri) We should delay rtyp expansion to when we actually need the
138                 //           receiver; thus all checks here should be delayed to later.
139                 rtyp, _ := deref(recv.typ)
140                 rtyp = expand(rtyp)
141
142                 // spec: "The receiver type must be of the form T or *T where T is a type name."
143                 // (ignore invalid types - error was reported before)
144                 if t := rtyp; t != Typ[Invalid] {
145                         var err string
146                         if T := asNamed(t); T != nil {
147                                 // spec: "The type denoted by T is called the receiver base type; it must not
148                                 // be a pointer or interface type and it must be declared in the same package
149                                 // as the method."
150                                 if T.obj.pkg != check.pkg {
151                                         err = "type not defined in this package"
152                                         if check.conf.CompilerErrorMessages {
153                                                 check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
154                                                 err = ""
155                                         }
156                                 } else {
157                                         switch u := optype(T).(type) {
158                                         case *Basic:
159                                                 // unsafe.Pointer is treated like a regular pointer
160                                                 if u.kind == UnsafePointer {
161                                                         err = "unsafe.Pointer"
162                                                 }
163                                         case *Pointer, *Interface:
164                                                 err = "pointer or interface type"
165                                         }
166                                 }
167                         } else if T := asBasic(t); T != nil {
168                                 err = "basic or unnamed type"
169                                 if check.conf.CompilerErrorMessages {
170                                         check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
171                                         err = ""
172                                 }
173                         } else {
174                                 check.errorf(recv.pos, "invalid receiver type %s", recv.typ)
175                         }
176                         if err != "" {
177                                 check.errorf(recv.pos, "invalid receiver type %s (%s)", recv.typ, err)
178                                 // ok to continue
179                         }
180                 }
181                 sig.recv = recv
182         }
183
184         sig.params = NewTuple(params...)
185         sig.results = NewTuple(results...)
186         sig.variadic = variadic
187 }
188
189 // collectParams declares the parameters of list in scope and returns the corresponding
190 // variable list. If type0 != nil, it is used instead of the first type in list.
191 func (check *Checker) collectParams(scope *Scope, list []*syntax.Field, type0 syntax.Expr, variadicOk bool) (params []*Var, variadic bool) {
192         if list == nil {
193                 return
194         }
195
196         var named, anonymous bool
197
198         var typ Type
199         var prev syntax.Expr
200         for i, field := range list {
201                 ftype := field.Type
202                 // type-check type of grouped fields only once
203                 if ftype != prev {
204                         prev = ftype
205                         if i == 0 && type0 != nil {
206                                 ftype = type0
207                         }
208                         if t, _ := ftype.(*syntax.DotsType); t != nil {
209                                 ftype = t.Elem
210                                 if variadicOk && i == len(list)-1 {
211                                         variadic = true
212                                 } else {
213                                         check.softErrorf(t, "can only use ... with final parameter in list")
214                                         // ignore ... and continue
215                                 }
216                         }
217                         typ = check.varType(ftype)
218                 }
219                 // The parser ensures that f.Tag is nil and we don't
220                 // care if a constructed AST contains a non-nil tag.
221                 if field.Name != nil {
222                         // named parameter
223                         name := field.Name.Value
224                         if name == "" {
225                                 check.error(field.Name, invalidAST+"anonymous parameter")
226                                 // ok to continue
227                         }
228                         par := NewParam(field.Name.Pos(), check.pkg, name, typ)
229                         check.declare(scope, field.Name, par, scope.pos)
230                         params = append(params, par)
231                         named = true
232                 } else {
233                         // anonymous parameter
234                         par := NewParam(field.Pos(), check.pkg, "", typ)
235                         check.recordImplicit(field, par)
236                         params = append(params, par)
237                         anonymous = true
238                 }
239         }
240
241         if named && anonymous {
242                 check.error(list[0], invalidAST+"list contains both named and anonymous parameters")
243                 // ok to continue
244         }
245
246         // For a variadic function, change the last parameter's type from T to []T.
247         // Since we type-checked T rather than ...T, we also need to retro-actively
248         // record the type for ...T.
249         if variadic {
250                 last := params[len(params)-1]
251                 last.typ = &Slice{elem: last.typ}
252                 check.recordTypeAndValue(list[len(list)-1].Type, typexpr, last.typ, nil)
253         }
254
255         return
256 }
257
258 // isubst returns an x with identifiers substituted per the substitution map smap.
259 // isubst only handles the case of (valid) method receiver type expressions correctly.
260 func isubst(x syntax.Expr, smap map[*syntax.Name]*syntax.Name) syntax.Expr {
261         switch n := x.(type) {
262         case *syntax.Name:
263                 if alt := smap[n]; alt != nil {
264                         return alt
265                 }
266         // case *syntax.StarExpr:
267         //      X := isubst(n.X, smap)
268         //      if X != n.X {
269         //              new := *n
270         //              new.X = X
271         //              return &new
272         //      }
273         case *syntax.Operation:
274                 if n.Op == syntax.Mul && n.Y == nil {
275                         X := isubst(n.X, smap)
276                         if X != n.X {
277                                 new := *n
278                                 new.X = X
279                                 return &new
280                         }
281                 }
282         case *syntax.IndexExpr:
283                 Index := isubst(n.Index, smap)
284                 if Index != n.Index {
285                         new := *n
286                         new.Index = Index
287                         return &new
288                 }
289         case *syntax.ListExpr:
290                 var elems []syntax.Expr
291                 for i, elem := range n.ElemList {
292                         new := isubst(elem, smap)
293                         if new != elem {
294                                 if elems == nil {
295                                         elems = make([]syntax.Expr, len(n.ElemList))
296                                         copy(elems, n.ElemList)
297                                 }
298                                 elems[i] = new
299                         }
300                 }
301                 if elems != nil {
302                         new := *n
303                         new.ElemList = elems
304                         return &new
305                 }
306         case *syntax.ParenExpr:
307                 return isubst(n.X, smap) // no need to keep parentheses
308         default:
309                 // Other receiver type expressions are invalid.
310                 // It's fine to ignore those here as they will
311                 // be checked elsewhere.
312         }
313         return x
314 }