]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/types2/builtins.go
types2, go/types: record final type for min/max arguments
[gostls13.git] / src / cmd / compile / internal / types2 / builtins.go
1 // Copyright 2012 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 // This file implements typechecking of builtin function calls.
6
7 package types2
8
9 import (
10         "cmd/compile/internal/syntax"
11         "go/constant"
12         "go/token"
13         . "internal/types/errors"
14 )
15
16 // builtin type-checks a call to the built-in specified by id and
17 // reports whether the call is valid, with *x holding the result;
18 // but x.expr is not set. If the call is invalid, the result is
19 // false, and *x is undefined.
20 func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (_ bool) {
21         argList := call.ArgList
22
23         // append is the only built-in that permits the use of ... for the last argument
24         bin := predeclaredFuncs[id]
25         if call.HasDots && id != _Append {
26                 //check.errorf(call.Ellipsis, invalidOp + "invalid use of ... with built-in %s", bin.name)
27                 check.errorf(call,
28                         InvalidDotDotDot,
29                         invalidOp+"invalid use of ... with built-in %s", bin.name)
30                 check.use(argList...)
31                 return
32         }
33
34         // For len(x) and cap(x) we need to know if x contains any function calls or
35         // receive operations. Save/restore current setting and set hasCallOrRecv to
36         // false for the evaluation of x so that we can check it afterwards.
37         // Note: We must do this _before_ calling exprList because exprList evaluates
38         //       all arguments.
39         if id == _Len || id == _Cap {
40                 defer func(b bool) {
41                         check.hasCallOrRecv = b
42                 }(check.hasCallOrRecv)
43                 check.hasCallOrRecv = false
44         }
45
46         // Evaluate arguments for built-ins that use ordinary (value) arguments.
47         // For built-ins with special argument handling (make, new, etc.),
48         // evaluation is done by the respective built-in code.
49         var args []*operand // not valid for _Make, _New, _Offsetof, _Trace
50         var nargs int
51         switch id {
52         default:
53                 // check all arguments
54                 args = check.exprList(argList)
55                 nargs = len(args)
56                 for _, a := range args {
57                         if a.mode == invalid {
58                                 return
59                         }
60                 }
61                 // first argument is always in x
62                 if nargs > 0 {
63                         *x = *args[0]
64                 }
65         case _Make, _New, _Offsetof, _Trace:
66                 // arguments require special handling
67                 nargs = len(argList)
68         }
69
70         // check argument count
71         {
72                 msg := ""
73                 if nargs < bin.nargs {
74                         msg = "not enough"
75                 } else if !bin.variadic && nargs > bin.nargs {
76                         msg = "too many"
77                 }
78                 if msg != "" {
79                         check.errorf(call, WrongArgCount, invalidOp+"%s arguments for %v (expected %d, found %d)", msg, call, bin.nargs, nargs)
80                         return
81                 }
82         }
83
84         switch id {
85         case _Append:
86                 // append(s S, x ...T) S, where T is the element type of S
87                 // spec: "The variadic function append appends zero or more values x to s of type
88                 // S, which must be a slice type, and returns the resulting slice, also of type S.
89                 // The values x are passed to a parameter of type ...T where T is the element type
90                 // of S and the respective parameter passing rules apply."
91                 S := x.typ
92                 var T Type
93                 if s, _ := coreType(S).(*Slice); s != nil {
94                         T = s.elem
95                 } else {
96                         var cause string
97                         switch {
98                         case x.isNil():
99                                 cause = "have untyped nil"
100                         case isTypeParam(S):
101                                 if u := coreType(S); u != nil {
102                                         cause = check.sprintf("%s has core type %s", x, u)
103                                 } else {
104                                         cause = check.sprintf("%s has no core type", x)
105                                 }
106                         default:
107                                 cause = check.sprintf("have %s", x)
108                         }
109                         // don't use invalidArg prefix here as it would repeat "argument" in the error message
110                         check.errorf(x, InvalidAppend, "first argument to append must be a slice; %s", cause)
111                         return
112                 }
113
114                 // spec: "As a special case, append also accepts a first argument assignable
115                 // to type []byte with a second argument of string type followed by ... .
116                 // This form appends the bytes of the string.
117                 if nargs == 2 && call.HasDots {
118                         if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok {
119                                 y := args[1]
120                                 if t := coreString(y.typ); t != nil && isString(t) {
121                                         if check.recordTypes() {
122                                                 sig := makeSig(S, S, y.typ)
123                                                 sig.variadic = true
124                                                 check.recordBuiltinType(call.Fun, sig)
125                                         }
126                                         x.mode = value
127                                         x.typ = S
128                                         break
129                                 }
130                         }
131                 }
132
133                 // check general case by creating custom signature
134                 sig := makeSig(S, S, NewSlice(T)) // []T required for variadic signature
135                 sig.variadic = true
136                 check.arguments(call, sig, nil, nil, args, nil, nil) // discard result (we know the result type)
137                 // ok to continue even if check.arguments reported errors
138
139                 x.mode = value
140                 x.typ = S
141                 if check.recordTypes() {
142                         check.recordBuiltinType(call.Fun, sig)
143                 }
144
145         case _Cap, _Len:
146                 // cap(x)
147                 // len(x)
148                 mode := invalid
149                 var val constant.Value
150                 switch t := arrayPtrDeref(under(x.typ)).(type) {
151                 case *Basic:
152                         if isString(t) && id == _Len {
153                                 if x.mode == constant_ {
154                                         mode = constant_
155                                         val = constant.MakeInt64(int64(len(constant.StringVal(x.val))))
156                                 } else {
157                                         mode = value
158                                 }
159                         }
160
161                 case *Array:
162                         mode = value
163                         // spec: "The expressions len(s) and cap(s) are constants
164                         // if the type of s is an array or pointer to an array and
165                         // the expression s does not contain channel receives or
166                         // function calls; in this case s is not evaluated."
167                         if !check.hasCallOrRecv {
168                                 mode = constant_
169                                 if t.len >= 0 {
170                                         val = constant.MakeInt64(t.len)
171                                 } else {
172                                         val = constant.MakeUnknown()
173                                 }
174                         }
175
176                 case *Slice, *Chan:
177                         mode = value
178
179                 case *Map:
180                         if id == _Len {
181                                 mode = value
182                         }
183
184                 case *Interface:
185                         if !isTypeParam(x.typ) {
186                                 break
187                         }
188                         if t.typeSet().underIs(func(t Type) bool {
189                                 switch t := arrayPtrDeref(t).(type) {
190                                 case *Basic:
191                                         if isString(t) && id == _Len {
192                                                 return true
193                                         }
194                                 case *Array, *Slice, *Chan:
195                                         return true
196                                 case *Map:
197                                         if id == _Len {
198                                                 return true
199                                         }
200                                 }
201                                 return false
202                         }) {
203                                 mode = value
204                         }
205                 }
206
207                 if mode == invalid {
208                         // avoid error if underlying type is invalid
209                         if under(x.typ) != Typ[Invalid] {
210                                 code := InvalidCap
211                                 if id == _Len {
212                                         code = InvalidLen
213                                 }
214                                 check.errorf(x, code, invalidArg+"%s for %s", x, bin.name)
215                         }
216                         return
217                 }
218
219                 // record the signature before changing x.typ
220                 if check.recordTypes() && mode != constant_ {
221                         check.recordBuiltinType(call.Fun, makeSig(Typ[Int], x.typ))
222                 }
223
224                 x.mode = mode
225                 x.typ = Typ[Int]
226                 x.val = val
227
228         case _Clear:
229                 // clear(m)
230                 check.verifyVersionf(call.Fun, go1_21, "clear")
231
232                 if !underIs(x.typ, func(u Type) bool {
233                         switch u.(type) {
234                         case *Map, *Slice:
235                                 return true
236                         }
237                         check.errorf(x, InvalidClear, invalidArg+"cannot clear %s: argument must be (or constrained by) map or slice", x)
238                         return false
239                 }) {
240                         return
241                 }
242
243                 x.mode = novalue
244                 if check.recordTypes() {
245                         check.recordBuiltinType(call.Fun, makeSig(nil, x.typ))
246                 }
247
248         case _Close:
249                 // close(c)
250                 if !underIs(x.typ, func(u Type) bool {
251                         uch, _ := u.(*Chan)
252                         if uch == nil {
253                                 check.errorf(x, InvalidClose, invalidOp+"cannot close non-channel %s", x)
254                                 return false
255                         }
256                         if uch.dir == RecvOnly {
257                                 check.errorf(x, InvalidClose, invalidOp+"cannot close receive-only channel %s", x)
258                                 return false
259                         }
260                         return true
261                 }) {
262                         return
263                 }
264                 x.mode = novalue
265                 if check.recordTypes() {
266                         check.recordBuiltinType(call.Fun, makeSig(nil, x.typ))
267                 }
268
269         case _Complex:
270                 // complex(x, y floatT) complexT
271                 y := args[1]
272
273                 // convert or check untyped arguments
274                 d := 0
275                 if isUntyped(x.typ) {
276                         d |= 1
277                 }
278                 if isUntyped(y.typ) {
279                         d |= 2
280                 }
281                 switch d {
282                 case 0:
283                         // x and y are typed => nothing to do
284                 case 1:
285                         // only x is untyped => convert to type of y
286                         check.convertUntyped(x, y.typ)
287                 case 2:
288                         // only y is untyped => convert to type of x
289                         check.convertUntyped(y, x.typ)
290                 case 3:
291                         // x and y are untyped =>
292                         // 1) if both are constants, convert them to untyped
293                         //    floating-point numbers if possible,
294                         // 2) if one of them is not constant (possible because
295                         //    it contains a shift that is yet untyped), convert
296                         //    both of them to float64 since they must have the
297                         //    same type to succeed (this will result in an error
298                         //    because shifts of floats are not permitted)
299                         if x.mode == constant_ && y.mode == constant_ {
300                                 toFloat := func(x *operand) {
301                                         if isNumeric(x.typ) && constant.Sign(constant.Imag(x.val)) == 0 {
302                                                 x.typ = Typ[UntypedFloat]
303                                         }
304                                 }
305                                 toFloat(x)
306                                 toFloat(y)
307                         } else {
308                                 check.convertUntyped(x, Typ[Float64])
309                                 check.convertUntyped(y, Typ[Float64])
310                                 // x and y should be invalid now, but be conservative
311                                 // and check below
312                         }
313                 }
314                 if x.mode == invalid || y.mode == invalid {
315                         return
316                 }
317
318                 // both argument types must be identical
319                 if !Identical(x.typ, y.typ) {
320                         check.errorf(x, InvalidComplex, invalidOp+"%v (mismatched types %s and %s)", call, x.typ, y.typ)
321                         return
322                 }
323
324                 // the argument types must be of floating-point type
325                 // (applyTypeFunc never calls f with a type parameter)
326                 f := func(typ Type) Type {
327                         assert(!isTypeParam(typ))
328                         if t, _ := under(typ).(*Basic); t != nil {
329                                 switch t.kind {
330                                 case Float32:
331                                         return Typ[Complex64]
332                                 case Float64:
333                                         return Typ[Complex128]
334                                 case UntypedFloat:
335                                         return Typ[UntypedComplex]
336                                 }
337                         }
338                         return nil
339                 }
340                 resTyp := check.applyTypeFunc(f, x, id)
341                 if resTyp == nil {
342                         check.errorf(x, InvalidComplex, invalidArg+"arguments have type %s, expected floating-point", x.typ)
343                         return
344                 }
345
346                 // if both arguments are constants, the result is a constant
347                 if x.mode == constant_ && y.mode == constant_ {
348                         x.val = constant.BinaryOp(constant.ToFloat(x.val), token.ADD, constant.MakeImag(constant.ToFloat(y.val)))
349                 } else {
350                         x.mode = value
351                 }
352
353                 if check.recordTypes() && x.mode != constant_ {
354                         check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ, x.typ))
355                 }
356
357                 x.typ = resTyp
358
359         case _Copy:
360                 // copy(x, y []T) int
361                 dst, _ := coreType(x.typ).(*Slice)
362
363                 y := args[1]
364                 src0 := coreString(y.typ)
365                 if src0 != nil && isString(src0) {
366                         src0 = NewSlice(universeByte)
367                 }
368                 src, _ := src0.(*Slice)
369
370                 if dst == nil || src == nil {
371                         check.errorf(x, InvalidCopy, invalidArg+"copy expects slice arguments; found %s and %s", x, y)
372                         return
373                 }
374
375                 if !Identical(dst.elem, src.elem) {
376                         check.errorf(x, InvalidCopy, invalidArg+"arguments to copy %s and %s have different element types %s and %s", x, y, dst.elem, src.elem)
377                         return
378                 }
379
380                 if check.recordTypes() {
381                         check.recordBuiltinType(call.Fun, makeSig(Typ[Int], x.typ, y.typ))
382                 }
383                 x.mode = value
384                 x.typ = Typ[Int]
385
386         case _Delete:
387                 // delete(map_, key)
388                 // map_ must be a map type or a type parameter describing map types.
389                 // The key cannot be a type parameter for now.
390                 map_ := x.typ
391                 var key Type
392                 if !underIs(map_, func(u Type) bool {
393                         map_, _ := u.(*Map)
394                         if map_ == nil {
395                                 check.errorf(x, InvalidDelete, invalidArg+"%s is not a map", x)
396                                 return false
397                         }
398                         if key != nil && !Identical(map_.key, key) {
399                                 check.errorf(x, InvalidDelete, invalidArg+"maps of %s must have identical key types", x)
400                                 return false
401                         }
402                         key = map_.key
403                         return true
404                 }) {
405                         return
406                 }
407
408                 *x = *args[1] // key
409                 check.assignment(x, key, "argument to delete")
410                 if x.mode == invalid {
411                         return
412                 }
413
414                 x.mode = novalue
415                 if check.recordTypes() {
416                         check.recordBuiltinType(call.Fun, makeSig(nil, map_, key))
417                 }
418
419         case _Imag, _Real:
420                 // imag(complexT) floatT
421                 // real(complexT) floatT
422
423                 // convert or check untyped argument
424                 if isUntyped(x.typ) {
425                         if x.mode == constant_ {
426                                 // an untyped constant number can always be considered
427                                 // as a complex constant
428                                 if isNumeric(x.typ) {
429                                         x.typ = Typ[UntypedComplex]
430                                 }
431                         } else {
432                                 // an untyped non-constant argument may appear if
433                                 // it contains a (yet untyped non-constant) shift
434                                 // expression: convert it to complex128 which will
435                                 // result in an error (shift of complex value)
436                                 check.convertUntyped(x, Typ[Complex128])
437                                 // x should be invalid now, but be conservative and check
438                                 if x.mode == invalid {
439                                         return
440                                 }
441                         }
442                 }
443
444                 // the argument must be of complex type
445                 // (applyTypeFunc never calls f with a type parameter)
446                 f := func(typ Type) Type {
447                         assert(!isTypeParam(typ))
448                         if t, _ := under(typ).(*Basic); t != nil {
449                                 switch t.kind {
450                                 case Complex64:
451                                         return Typ[Float32]
452                                 case Complex128:
453                                         return Typ[Float64]
454                                 case UntypedComplex:
455                                         return Typ[UntypedFloat]
456                                 }
457                         }
458                         return nil
459                 }
460                 resTyp := check.applyTypeFunc(f, x, id)
461                 if resTyp == nil {
462                         code := InvalidImag
463                         if id == _Real {
464                                 code = InvalidReal
465                         }
466                         check.errorf(x, code, invalidArg+"argument has type %s, expected complex type", x.typ)
467                         return
468                 }
469
470                 // if the argument is a constant, the result is a constant
471                 if x.mode == constant_ {
472                         if id == _Real {
473                                 x.val = constant.Real(x.val)
474                         } else {
475                                 x.val = constant.Imag(x.val)
476                         }
477                 } else {
478                         x.mode = value
479                 }
480
481                 if check.recordTypes() && x.mode != constant_ {
482                         check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ))
483                 }
484
485                 x.typ = resTyp
486
487         case _Make:
488                 // make(T, n)
489                 // make(T, n, m)
490                 // (no argument evaluated yet)
491                 arg0 := argList[0]
492                 T := check.varType(arg0)
493                 if T == Typ[Invalid] {
494                         return
495                 }
496
497                 var min int // minimum number of arguments
498                 switch coreType(T).(type) {
499                 case *Slice:
500                         min = 2
501                 case *Map, *Chan:
502                         min = 1
503                 case nil:
504                         check.errorf(arg0, InvalidMake, invalidArg+"cannot make %s: no core type", arg0)
505                         return
506                 default:
507                         check.errorf(arg0, InvalidMake, invalidArg+"cannot make %s; type must be slice, map, or channel", arg0)
508                         return
509                 }
510                 if nargs < min || min+1 < nargs {
511                         check.errorf(call, WrongArgCount, invalidOp+"%v expects %d or %d arguments; found %d", call, min, min+1, nargs)
512                         return
513                 }
514
515                 types := []Type{T}
516                 var sizes []int64 // constant integer arguments, if any
517                 for _, arg := range argList[1:] {
518                         typ, size := check.index(arg, -1) // ok to continue with typ == Typ[Invalid]
519                         types = append(types, typ)
520                         if size >= 0 {
521                                 sizes = append(sizes, size)
522                         }
523                 }
524                 if len(sizes) == 2 && sizes[0] > sizes[1] {
525                         check.error(argList[1], SwappedMakeArgs, invalidArg+"length and capacity swapped")
526                         // safe to continue
527                 }
528                 x.mode = value
529                 x.typ = T
530                 if check.recordTypes() {
531                         check.recordBuiltinType(call.Fun, makeSig(x.typ, types...))
532                 }
533
534         case _Max, _Min:
535                 // max(x, ...)
536                 // min(x, ...)
537                 check.verifyVersionf(call.Fun, go1_21, bin.name)
538
539                 op := token.LSS
540                 if id == _Max {
541                         op = token.GTR
542                 }
543
544                 for i, a := range args {
545                         if a.mode == invalid {
546                                 return
547                         }
548
549                         if !allOrdered(a.typ) {
550                                 check.errorf(a, InvalidMinMaxOperand, invalidArg+"%s cannot be ordered", a)
551                                 return
552                         }
553
554                         // The first argument is already in x and there's nothing left to do.
555                         if i > 0 {
556                                 check.matchTypes(x, a)
557                                 if x.mode == invalid {
558                                         return
559                                 }
560
561                                 if !Identical(x.typ, a.typ) {
562                                         check.errorf(a, MismatchedTypes, invalidArg+"mismatched types %s (previous argument) and %s (type of %s)", x.typ, a.typ, a.expr)
563                                         return
564                                 }
565
566                                 if x.mode == constant_ && a.mode == constant_ {
567                                         if constant.Compare(a.val, op, x.val) {
568                                                 *x = *a
569                                         }
570                                 } else {
571                                         x.mode = value
572                                 }
573                         }
574                 }
575
576                 // If nargs == 1, make sure x.mode is either a value or a constant.
577                 if x.mode != constant_ {
578                         x.mode = value
579                 }
580
581                 // Use the final type computed above for all arguments.
582                 for _, a := range args {
583                         check.updateExprType(a.expr, x.typ, true)
584                 }
585
586                 if check.recordTypes() && x.mode != constant_ {
587                         types := make([]Type, nargs)
588                         for i := range types {
589                                 types[i] = x.typ
590                         }
591                         check.recordBuiltinType(call.Fun, makeSig(x.typ, types...))
592                 }
593
594         case _New:
595                 // new(T)
596                 // (no argument evaluated yet)
597                 T := check.varType(argList[0])
598                 if T == Typ[Invalid] {
599                         return
600                 }
601
602                 x.mode = value
603                 x.typ = &Pointer{base: T}
604                 if check.recordTypes() {
605                         check.recordBuiltinType(call.Fun, makeSig(x.typ, T))
606                 }
607
608         case _Panic:
609                 // panic(x)
610                 // record panic call if inside a function with result parameters
611                 // (for use in Checker.isTerminating)
612                 if check.sig != nil && check.sig.results.Len() > 0 {
613                         // function has result parameters
614                         p := check.isPanic
615                         if p == nil {
616                                 // allocate lazily
617                                 p = make(map[*syntax.CallExpr]bool)
618                                 check.isPanic = p
619                         }
620                         p[call] = true
621                 }
622
623                 check.assignment(x, &emptyInterface, "argument to panic")
624                 if x.mode == invalid {
625                         return
626                 }
627
628                 x.mode = novalue
629                 if check.recordTypes() {
630                         check.recordBuiltinType(call.Fun, makeSig(nil, &emptyInterface))
631                 }
632
633         case _Print, _Println:
634                 // print(x, y, ...)
635                 // println(x, y, ...)
636                 var params []Type
637                 if nargs > 0 {
638                         params = make([]Type, nargs)
639                         for i, a := range args {
640                                 check.assignment(a, nil, "argument to "+predeclaredFuncs[id].name)
641                                 if a.mode == invalid {
642                                         return
643                                 }
644                                 params[i] = a.typ
645                         }
646                 }
647
648                 x.mode = novalue
649                 if check.recordTypes() {
650                         check.recordBuiltinType(call.Fun, makeSig(nil, params...))
651                 }
652
653         case _Recover:
654                 // recover() interface{}
655                 x.mode = value
656                 x.typ = &emptyInterface
657                 if check.recordTypes() {
658                         check.recordBuiltinType(call.Fun, makeSig(x.typ))
659                 }
660
661         case _Add:
662                 // unsafe.Add(ptr unsafe.Pointer, len IntegerType) unsafe.Pointer
663                 check.verifyVersionf(call.Fun, go1_17, "unsafe.Add")
664
665                 check.assignment(x, Typ[UnsafePointer], "argument to unsafe.Add")
666                 if x.mode == invalid {
667                         return
668                 }
669
670                 y := args[1]
671                 if !check.isValidIndex(y, InvalidUnsafeAdd, "length", true) {
672                         return
673                 }
674
675                 x.mode = value
676                 x.typ = Typ[UnsafePointer]
677                 if check.recordTypes() {
678                         check.recordBuiltinType(call.Fun, makeSig(x.typ, x.typ, y.typ))
679                 }
680
681         case _Alignof:
682                 // unsafe.Alignof(x T) uintptr
683                 check.assignment(x, nil, "argument to unsafe.Alignof")
684                 if x.mode == invalid {
685                         return
686                 }
687
688                 if hasVarSize(x.typ, nil) {
689                         x.mode = value
690                         if check.recordTypes() {
691                                 check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], x.typ))
692                         }
693                 } else {
694                         x.mode = constant_
695                         x.val = constant.MakeInt64(check.conf.alignof(x.typ))
696                         // result is constant - no need to record signature
697                 }
698                 x.typ = Typ[Uintptr]
699
700         case _Offsetof:
701                 // unsafe.Offsetof(x T) uintptr, where x must be a selector
702                 // (no argument evaluated yet)
703                 arg0 := argList[0]
704                 selx, _ := unparen(arg0).(*syntax.SelectorExpr)
705                 if selx == nil {
706                         check.errorf(arg0, BadOffsetofSyntax, invalidArg+"%s is not a selector expression", arg0)
707                         check.use(arg0)
708                         return
709                 }
710
711                 check.expr(nil, x, selx.X)
712                 if x.mode == invalid {
713                         return
714                 }
715
716                 base := derefStructPtr(x.typ)
717                 sel := selx.Sel.Value
718                 obj, index, indirect := LookupFieldOrMethod(base, false, check.pkg, sel)
719                 switch obj.(type) {
720                 case nil:
721                         check.errorf(x, MissingFieldOrMethod, invalidArg+"%s has no single field %s", base, sel)
722                         return
723                 case *Func:
724                         // TODO(gri) Using derefStructPtr may result in methods being found
725                         // that don't actually exist. An error either way, but the error
726                         // message is confusing. See: https://play.golang.org/p/al75v23kUy ,
727                         // but go/types reports: "invalid argument: x.m is a method value".
728                         check.errorf(arg0, InvalidOffsetof, invalidArg+"%s is a method value", arg0)
729                         return
730                 }
731                 if indirect {
732                         check.errorf(x, InvalidOffsetof, invalidArg+"field %s is embedded via a pointer in %s", sel, base)
733                         return
734                 }
735
736                 // TODO(gri) Should we pass x.typ instead of base (and have indirect report if derefStructPtr indirected)?
737                 check.recordSelection(selx, FieldVal, base, obj, index, false)
738
739                 // record the selector expression (was bug - go.dev/issue/47895)
740                 {
741                         mode := value
742                         if x.mode == variable || indirect {
743                                 mode = variable
744                         }
745                         check.record(&operand{mode, selx, obj.Type(), nil, 0})
746                 }
747
748                 // The field offset is considered a variable even if the field is declared before
749                 // the part of the struct which is variable-sized. This makes both the rules
750                 // simpler and also permits (or at least doesn't prevent) a compiler from re-
751                 // arranging struct fields if it wanted to.
752                 if hasVarSize(base, nil) {
753                         x.mode = value
754                         if check.recordTypes() {
755                                 check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], obj.Type()))
756                         }
757                 } else {
758                         offs := check.conf.offsetof(base, index)
759                         if offs < 0 {
760                                 check.errorf(x, TypeTooLarge, "%s is too large", x)
761                                 return
762                         }
763                         x.mode = constant_
764                         x.val = constant.MakeInt64(offs)
765                         // result is constant - no need to record signature
766                 }
767                 x.typ = Typ[Uintptr]
768
769         case _Sizeof:
770                 // unsafe.Sizeof(x T) uintptr
771                 check.assignment(x, nil, "argument to unsafe.Sizeof")
772                 if x.mode == invalid {
773                         return
774                 }
775
776                 if hasVarSize(x.typ, nil) {
777                         x.mode = value
778                         if check.recordTypes() {
779                                 check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], x.typ))
780                         }
781                 } else {
782                         size := check.conf.sizeof(x.typ)
783                         if size < 0 {
784                                 check.errorf(x, TypeTooLarge, "%s is too large", x)
785                                 return
786                         }
787                         x.mode = constant_
788                         x.val = constant.MakeInt64(size)
789                         // result is constant - no need to record signature
790                 }
791                 x.typ = Typ[Uintptr]
792
793         case _Slice:
794                 // unsafe.Slice(ptr *T, len IntegerType) []T
795                 check.verifyVersionf(call.Fun, go1_17, "unsafe.Slice")
796
797                 ptr, _ := under(x.typ).(*Pointer) // TODO(gri) should this be coreType rather than under?
798                 if ptr == nil {
799                         check.errorf(x, InvalidUnsafeSlice, invalidArg+"%s is not a pointer", x)
800                         return
801                 }
802
803                 y := args[1]
804                 if !check.isValidIndex(y, InvalidUnsafeSlice, "length", false) {
805                         return
806                 }
807
808                 x.mode = value
809                 x.typ = NewSlice(ptr.base)
810                 if check.recordTypes() {
811                         check.recordBuiltinType(call.Fun, makeSig(x.typ, ptr, y.typ))
812                 }
813
814         case _SliceData:
815                 // unsafe.SliceData(slice []T) *T
816                 check.verifyVersionf(call.Fun, go1_20, "unsafe.SliceData")
817
818                 slice, _ := under(x.typ).(*Slice) // TODO(gri) should this be coreType rather than under?
819                 if slice == nil {
820                         check.errorf(x, InvalidUnsafeSliceData, invalidArg+"%s is not a slice", x)
821                         return
822                 }
823
824                 x.mode = value
825                 x.typ = NewPointer(slice.elem)
826                 if check.recordTypes() {
827                         check.recordBuiltinType(call.Fun, makeSig(x.typ, slice))
828                 }
829
830         case _String:
831                 // unsafe.String(ptr *byte, len IntegerType) string
832                 check.verifyVersionf(call.Fun, go1_20, "unsafe.String")
833
834                 check.assignment(x, NewPointer(universeByte), "argument to unsafe.String")
835                 if x.mode == invalid {
836                         return
837                 }
838
839                 y := args[1]
840                 if !check.isValidIndex(y, InvalidUnsafeString, "length", false) {
841                         return
842                 }
843
844                 x.mode = value
845                 x.typ = Typ[String]
846                 if check.recordTypes() {
847                         check.recordBuiltinType(call.Fun, makeSig(x.typ, NewPointer(universeByte), y.typ))
848                 }
849
850         case _StringData:
851                 // unsafe.StringData(str string) *byte
852                 check.verifyVersionf(call.Fun, go1_20, "unsafe.StringData")
853
854                 check.assignment(x, Typ[String], "argument to unsafe.StringData")
855                 if x.mode == invalid {
856                         return
857                 }
858
859                 x.mode = value
860                 x.typ = NewPointer(universeByte)
861                 if check.recordTypes() {
862                         check.recordBuiltinType(call.Fun, makeSig(x.typ, Typ[String]))
863                 }
864
865         case _Assert:
866                 // assert(pred) causes a typechecker error if pred is false.
867                 // The result of assert is the value of pred if there is no error.
868                 // Note: assert is only available in self-test mode.
869                 if x.mode != constant_ || !isBoolean(x.typ) {
870                         check.errorf(x, Test, invalidArg+"%s is not a boolean constant", x)
871                         return
872                 }
873                 if x.val.Kind() != constant.Bool {
874                         check.errorf(x, Test, "internal error: value of %s should be a boolean constant", x)
875                         return
876                 }
877                 if !constant.BoolVal(x.val) {
878                         check.errorf(call, Test, "%v failed", call)
879                         // compile-time assertion failure - safe to continue
880                 }
881                 // result is constant - no need to record signature
882
883         case _Trace:
884                 // trace(x, y, z, ...) dumps the positions, expressions, and
885                 // values of its arguments. The result of trace is the value
886                 // of the first argument.
887                 // Note: trace is only available in self-test mode.
888                 // (no argument evaluated yet)
889                 if nargs == 0 {
890                         check.dump("%v: trace() without arguments", atPos(call))
891                         x.mode = novalue
892                         break
893                 }
894                 var t operand
895                 x1 := x
896                 for _, arg := range argList {
897                         check.rawExpr(nil, x1, arg, nil, false) // permit trace for types, e.g.: new(trace(T))
898                         check.dump("%v: %s", atPos(x1), x1)
899                         x1 = &t // use incoming x only for first argument
900                 }
901                 if x.mode == invalid {
902                         return
903                 }
904                 // trace is only available in test mode - no need to record signature
905
906         default:
907                 unreachable()
908         }
909
910         assert(x.mode != invalid)
911         return true
912 }
913
914 // hasVarSize reports if the size of type t is variable due to type parameters
915 // or if the type is infinitely-sized due to a cycle for which the type has not
916 // yet been checked.
917 func hasVarSize(t Type, seen map[*Named]bool) (varSized bool) {
918         // Cycles are only possible through *Named types.
919         // The seen map is used to detect cycles and track
920         // the results of previously seen types.
921         if named, _ := t.(*Named); named != nil {
922                 if v, ok := seen[named]; ok {
923                         return v
924                 }
925                 if seen == nil {
926                         seen = make(map[*Named]bool)
927                 }
928                 seen[named] = true // possibly cyclic until proven otherwise
929                 defer func() {
930                         seen[named] = varSized // record final determination for named
931                 }()
932         }
933
934         switch u := under(t).(type) {
935         case *Array:
936                 return hasVarSize(u.elem, seen)
937         case *Struct:
938                 for _, f := range u.fields {
939                         if hasVarSize(f.typ, seen) {
940                                 return true
941                         }
942                 }
943         case *Interface:
944                 return isTypeParam(t)
945         case *Named, *Union:
946                 unreachable()
947         }
948         return false
949 }
950
951 // applyTypeFunc applies f to x. If x is a type parameter,
952 // the result is a type parameter constrained by an new
953 // interface bound. The type bounds for that interface
954 // are computed by applying f to each of the type bounds
955 // of x. If any of these applications of f return nil,
956 // applyTypeFunc returns nil.
957 // If x is not a type parameter, the result is f(x).
958 func (check *Checker) applyTypeFunc(f func(Type) Type, x *operand, id builtinId) Type {
959         if tp, _ := x.typ.(*TypeParam); tp != nil {
960                 // Test if t satisfies the requirements for the argument
961                 // type and collect possible result types at the same time.
962                 var terms []*Term
963                 if !tp.is(func(t *term) bool {
964                         if t == nil {
965                                 return false
966                         }
967                         if r := f(t.typ); r != nil {
968                                 terms = append(terms, NewTerm(t.tilde, r))
969                                 return true
970                         }
971                         return false
972                 }) {
973                         return nil
974                 }
975
976                 // We can type-check this fine but we're introducing a synthetic
977                 // type parameter for the result. It's not clear what the API
978                 // implications are here. Report an error for 1.18 (see go.dev/issue/50912),
979                 // but continue type-checking.
980                 var code Code
981                 switch id {
982                 case _Real:
983                         code = InvalidReal
984                 case _Imag:
985                         code = InvalidImag
986                 case _Complex:
987                         code = InvalidComplex
988                 default:
989                         unreachable()
990                 }
991                 check.softErrorf(x, code, "%s not supported as argument to %s for go1.18 (see go.dev/issue/50937)", x, predeclaredFuncs[id].name)
992
993                 // Construct a suitable new type parameter for the result type.
994                 // The type parameter is placed in the current package so export/import
995                 // works as expected.
996                 tpar := NewTypeName(nopos, check.pkg, tp.obj.name, nil)
997                 ptyp := check.newTypeParam(tpar, NewInterfaceType(nil, []Type{NewUnion(terms)})) // assigns type to tpar as a side-effect
998                 ptyp.index = tp.index
999
1000                 return ptyp
1001         }
1002
1003         return f(x.typ)
1004 }
1005
1006 // makeSig makes a signature for the given argument and result types.
1007 // Default types are used for untyped arguments, and res may be nil.
1008 func makeSig(res Type, args ...Type) *Signature {
1009         list := make([]*Var, len(args))
1010         for i, param := range args {
1011                 list[i] = NewVar(nopos, nil, "", Default(param))
1012         }
1013         params := NewTuple(list...)
1014         var result *Tuple
1015         if res != nil {
1016                 assert(!isUntyped(res))
1017                 result = NewTuple(NewVar(nopos, nil, "", res))
1018         }
1019         return &Signature{params: params, results: result}
1020 }
1021
1022 // arrayPtrDeref returns A if typ is of the form *A and A is an array;
1023 // otherwise it returns typ.
1024 func arrayPtrDeref(typ Type) Type {
1025         if p, ok := typ.(*Pointer); ok {
1026                 if a, _ := under(p.base).(*Array); a != nil {
1027                         return a
1028                 }
1029         }
1030         return typ
1031 }
1032
1033 // unparen returns e with any enclosing parentheses stripped.
1034 func unparen(e syntax.Expr) syntax.Expr {
1035         for {
1036                 p, ok := e.(*syntax.ParenExpr)
1037                 if !ok {
1038                         return e
1039                 }
1040                 e = p.X
1041         }
1042 }