...

Source file src/cmd/compile/internal/types2/builtins.go

Documentation: cmd/compile/internal/types2

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

View as plain text