-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsignature.go
470 lines (430 loc) · 16.8 KB
/
signature.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
// 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 types2
import (
"cmd/compile/internal/syntax"
"fmt"
. "internal/types/errors"
"path/filepath"
"strings"
)
// ----------------------------------------------------------------------------
// API
// A Signature represents a (non-builtin) function or method type.
// The receiver is ignored when comparing signatures for identity.
type Signature struct {
// 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)
}
// 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 an unnamed slice or a type parameter whose
// type set has an unnamed slice as common underlying type.
// As a special case, for variadic signatures the last parameter may
// also be a string type, or a type parameter containing a mix of byte
// slices and string types in its type set.
// 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")
}
last := params.At(n - 1).typ
var S *Slice
typeset(last, func(t, _ Type) bool {
var s *Slice
if isString(t) {
s = NewSlice(universeByte)
} else {
s, _ = Unalias(t).(*Slice) // don't accept a named slice type
}
if S == nil {
S = s
} else if !Identical(S, s) {
S = nil
return false
}
return true
})
if S == nil {
panic(fmt.Sprintf("got %s, want variadic parameter of unnamed slice or string type", last))
}
}
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
// 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 (s *Signature) Recv() *Var { return s.recv }
// TypeParams returns the type parameters of signature s, or nil.
func (s *Signature) TypeParams() *TypeParamList { return s.tparams }
// 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 }
// Results returns the results of signature s, or nil.
func (s *Signature) Results() *Tuple { return s.results }
// Variadic reports whether the signature s is variadic.
func (s *Signature) Variadic() bool { return s.variadic }
func (s *Signature) Underlying() Type { return s }
func (s *Signature) String() string { return TypeString(s, nil) }
// ----------------------------------------------------------------------------
// Implementation
// 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")
check.scope.isFunc = true
check.recordScope(ftyp, check.scope)
sig.scope = check.scope
defer check.closeScope()
// collect method receiver, if any
var recv *Var
var rparams *TypeParamList
if recvPar != nil {
// all type parameters' scopes start after the method name
scopePos := ftyp.Pos()
recv, rparams = check.collectRecv(recvPar, scopePos)
}
// collect and declare function type parameters
if tparams != nil {
// The parser will complain about invalid type parameters for methods.
check.collectTypeParams(&sig.tparams, tparams)
}
// collect ordinary and result parameters
pnames, params, variadic := check.collectParams(ParamVar, ftyp.ParamList)
rnames, results, _ := check.collectParams(ResultVar, ftyp.ResultList)
// declare named receiver, ordinary, and result parameters
scopePos := syntax.EndPos(ftyp) // all parameter's scopes start after the signature
if recv != nil && recv.name != "" {
check.declare(check.scope, recvPar.Name, recv, scopePos)
}
check.declareParams(pnames, params, scopePos)
check.declareParams(rnames, results, scopePos)
sig.recv = recv
sig.rparams = rparams
sig.params = NewTuple(params...)
sig.results = NewTuple(results...)
sig.variadic = variadic
}
// collectRecv extracts the method receiver and its type parameters (if any) from rparam.
// It declares the type parameters (but not the receiver) in the current scope, and
// returns the receiver variable and its type parameter list (if any).
func (check *Checker) collectRecv(rparam *syntax.Field, scopePos syntax.Pos) (*Var, *TypeParamList) {
// Unpack the receiver parameter which is of the form
//
// "(" [rname] ["*"] rbase ["[" rtparams "]"] ")"
//
// The receiver name rname, the pointer indirection, and the
// receiver type parameters rtparams may not be present.
rptr, rbase, rtparams := check.unpackRecv(rparam.Type, true)
// Determine the receiver base type.
var recvType Type = Typ[Invalid]
var recvTParamsList *TypeParamList
if rtparams == nil {
// If there are no type parameters, we can simply typecheck rparam.Type.
// If that is a generic type, varType will complain.
// Further receiver constraints will be checked later, with validRecv.
// We use rparam.Type (rather than base) to correctly record pointer
// and parentheses in types2.Info (was bug, see go.dev/issue/68639).
recvType = check.varType(rparam.Type)
// Defining new methods on instantiated (alias or defined) types is not permitted.
// Follow literal pointer/alias type chain and check.
// (Correct code permits at most one pointer indirection, but for this check it
// doesn't matter if we have multiple pointers.)
a, _ := unpointer(recvType).(*Alias) // recvType is not generic per above
for a != nil {
baseType := unpointer(a.fromRHS)
if g, _ := baseType.(genericType); g != nil && g.TypeParams() != nil {
check.errorf(rbase, InvalidRecv, "cannot define new methods on instantiated type %s", g)
recvType = Typ[Invalid] // avoid follow-on errors by Checker.validRecv
break
}
a, _ = baseType.(*Alias)
}
} else {
// If there are type parameters, rbase must denote a generic base type.
// Important: rbase must be resolved before declaring any receiver type
// parameters (which may have the same name, see below).
var baseType *Named // nil if not valid
var cause string
if t := check.genericType(rbase, &cause); isValid(t) {
switch t := t.(type) {
case *Named:
baseType = t
case *Alias:
// Methods on generic aliases are not permitted.
// Only report an error if the alias type is valid.
if isValid(unalias(t)) {
check.errorf(rbase, InvalidRecv, "cannot define new methods on generic alias type %s", t)
}
// Ok to continue but do not set basetype in this case so that
// recvType remains invalid (was bug, see go.dev/issue/70417).
default:
panic("unreachable")
}
} else {
if cause != "" {
check.errorf(rbase, InvalidRecv, "%s", cause)
}
// Ok to continue but do not set baseType (see comment above).
}
// Collect the type parameters declared by the receiver (see also
// Checker.collectTypeParams). The scope of the type parameter T in
// "func (r T[T]) f() {}" starts after f, not at r, so we declare it
// after typechecking rbase (see go.dev/issue/52038).
recvTParams := make([]*TypeParam, len(rtparams))
for i, rparam := range rtparams {
tpar := check.declareTypeParam(rparam, scopePos)
recvTParams[i] = tpar
// For historic reasons, type parameters in receiver type expressions
// are considered both definitions and uses and thus must be recorded
// in the Info.Uses and Info.Types maps (see go.dev/issue/68670).
check.recordUse(rparam, tpar.obj)
check.recordTypeAndValue(rparam, typexpr, tpar, nil)
}
recvTParamsList = bindTParams(recvTParams)
// Get the type parameter bounds from the receiver base type
// and set them for the respective (local) receiver type parameters.
if baseType != nil {
baseTParams := baseType.TypeParams().list()
if len(recvTParams) == len(baseTParams) {
smap := makeRenameMap(baseTParams, recvTParams)
for i, recvTPar := range recvTParams {
baseTPar := baseTParams[i]
check.mono.recordCanon(recvTPar, baseTPar)
// baseTPar.bound is possibly parameterized by other type parameters
// defined by the generic base type. Substitute those parameters with
// the receiver type parameters declared by the current method.
recvTPar.bound = check.subst(recvTPar.obj.pos, baseTPar.bound, smap, nil, check.context())
}
} else {
got := measure(len(recvTParams), "type parameter")
check.errorf(rbase, BadRecv, "receiver declares %s, but receiver base type declares %d", got, len(baseTParams))
}
// The type parameters declared by the receiver also serve as
// type arguments for the receiver type. Instantiate the receiver.
check.verifyVersionf(rbase, go1_18, "type instantiation")
targs := make([]Type, len(recvTParams))
for i, targ := range recvTParams {
targs[i] = targ
}
recvType = check.instance(rparam.Type.Pos(), baseType, targs, nil, check.context())
check.recordInstance(rbase, targs, recvType)
// Reestablish pointerness if needed (but avoid a pointer to an invalid type).
if rptr && isValid(recvType) {
recvType = NewPointer(recvType)
}
check.recordParenthesizedRecvTypes(rparam.Type, recvType)
}
}
// Create the receiver parameter.
// recvType is invalid if baseType was never set.
var recv *Var
if rname := rparam.Name; rname != nil && rname.Value != "" {
// named receiver
recv = newVar(RecvVar, rname.Pos(), check.pkg, rname.Value, recvType)
// In this case, the receiver is declared by the caller
// because it must be declared after any type parameters
// (otherwise it might shadow one of them).
} else {
// anonymous receiver
recv = newVar(RecvVar, rparam.Pos(), check.pkg, "", recvType)
check.recordImplicit(rparam, recv)
}
// Delay validation of receiver type as it may cause premature expansion of types
// the receiver type is dependent on (see go.dev/issue/51232, go.dev/issue/51233).
check.later(func() {
check.validRecv(rbase, recv)
}).describef(recv, "validRecv(%s)", recv)
return recv, recvTParamsList
}
func unpointer(t Type) Type {
for {
p, _ := t.(*Pointer)
if p == nil {
return t
}
t = p.base
}
}
// recordParenthesizedRecvTypes records parenthesized intermediate receiver type
// expressions that all map to the same type, by recursively unpacking expr and
// recording the corresponding type for it. Example:
//
// expression --> type
// ----------------------
// (*(T[P])) *T[P]
// *(T[P]) *T[P]
// (T[P]) T[P]
// T[P] T[P]
func (check *Checker) recordParenthesizedRecvTypes(expr syntax.Expr, typ Type) {
for {
check.recordTypeAndValue(expr, typexpr, typ, nil)
switch e := expr.(type) {
case *syntax.ParenExpr:
expr = e.X
case *syntax.Operation:
if e.Op == syntax.Mul && e.Y == nil {
expr = e.X
// In a correct program, typ must be an unnamed
// pointer type. But be careful and don't panic.
ptr, _ := typ.(*Pointer)
if ptr == nil {
return // something is wrong
}
typ = ptr.base
break
}
return // cannot unpack any further
default:
return // cannot unpack any further
}
}
}
// collectParams collects (but does not declare) all parameter/result
// variables of list and returns the list of names and corresponding
// variables, and whether the (parameter) list is variadic.
// Anonymous parameters are recorded with nil names.
func (check *Checker) collectParams(kind VarKind, list []*syntax.Field) (names []*syntax.Name, params []*Var, variadic bool) {
if list == nil {
return
}
var named, anonymous bool
var typ Type
var prev syntax.Expr
for i, field := range list {
ftype := field.Type
// type-check type of grouped fields only once
if ftype != prev {
prev = ftype
if t, _ := ftype.(*syntax.DotsType); t != nil {
ftype = t.Elem
if kind == ParamVar && i == len(list)-1 {
variadic = true
} else {
check.error(t, InvalidSyntaxTree, "invalid use of ...")
// ignore ... and continue
}
}
typ = check.varType(ftype)
}
// The parser ensures that f.Tag is nil and we don't
// care if a constructed AST contains a non-nil tag.
if field.Name != nil {
// named parameter
name := field.Name.Value
if name == "" {
check.error(field.Name, InvalidSyntaxTree, "anonymous parameter")
// ok to continue
}
par := newVar(kind, field.Name.Pos(), check.pkg, name, typ)
// named parameter is declared by caller
names = append(names, field.Name)
params = append(params, par)
named = true
} else {
// anonymous parameter
par := newVar(kind, field.Pos(), check.pkg, "", typ)
check.recordImplicit(field, par)
names = append(names, nil)
params = append(params, par)
anonymous = true
}
}
if named && anonymous {
check.error(list[0], 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 variadic {
last := params[len(params)-1]
last.typ = &Slice{elem: last.typ}
check.recordTypeAndValue(list[len(list)-1].Type, typexpr, last.typ, nil)
}
return
}
// declareParams declares each named parameter in the current scope.
func (check *Checker) declareParams(names []*syntax.Name, params []*Var, scopePos syntax.Pos) {
for i, name := range names {
if name != nil && name.Value != "" {
check.declare(check.scope, name, params[i], scopePos)
}
}
}
// validRecv verifies that the receiver satisfies its respective spec requirements
// and reports an error otherwise.
func (check *Checker) validRecv(pos poser, recv *Var) {
// 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:
if T.obj.pkg != check.pkg || isCGoTypeObj(T.obj) {
check.errorf(pos, 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"
}
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.
panic("unreachable")
}
if cause != "" {
check.errorf(pos, InvalidRecv, "invalid receiver type %s (%s)", rtyp, cause)
}
case *Basic:
check.errorf(pos, InvalidRecv, "cannot define new methods on non-local type %s", rtyp)
default:
check.errorf(pos, InvalidRecv, "invalid receiver type %s", recv.typ)
}
}
// isCGoTypeObj reports whether the given type name was created by cgo.
func isCGoTypeObj(obj *TypeName) bool {
return strings.HasPrefix(obj.name, "_Ctype_") ||
strings.HasPrefix(filepath.Base(obj.pos.FileBase().Filename()), "_cgo_")
}