github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/types2/builtins.go (about)

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