package types
import (
)
func ( *Checker) ( *operand, *ast.CallExpr, builtinId) ( bool) {
:= predeclaredFuncs[]
if .Ellipsis.IsValid() && != _Append {
.invalidOp(atPos(.Ellipsis),
_InvalidDotDotDot,
"invalid use of ... with built-in %s", .name)
.use(.Args...)
return
}
if == _Len || == _Cap {
defer func( bool) {
.hasCallOrRecv =
}(.hasCallOrRecv)
.hasCallOrRecv = false
}
var func(*operand, int)
:= len(.Args)
switch {
default:
, := .exprList(.Args, false)
= func( *operand, int) { * = *[] }
= len()
if > 0 {
(, 0)
if .mode == invalid {
return
}
}
case _Make, _New, _Offsetof, _Trace:
}
{
:= ""
if < .nargs {
= "not enough"
} else if !.variadic && > .nargs {
= "too many"
}
if != "" {
.invalidOp(inNode(, .Rparen), _WrongArgCount, "%s arguments for %s (expected %d, found %d)", , , .nargs, )
return
}
}
switch {
case _Append:
:= .typ
var Type
if , := coreType().(*Slice); != nil {
= .elem
} else {
var string
switch {
case .isNil():
= "have untyped nil"
case isTypeParam():
if := coreType(); != nil {
= .sprintf("%s has core type %s", , )
} else {
= .sprintf("%s has no core type", )
}
default:
= .sprintf("have %s", )
}
.errorf(, _InvalidAppend, "first argument to append must be a slice; %s", )
return
}
:= []operand{*}
if == 2 && .Ellipsis.IsValid() {
if , := .assignableTo(, NewSlice(universeByte), nil); {
(, 1)
if .mode == invalid {
return
}
if := coreString(.typ); != nil && isString() {
if .Types != nil {
:= makeSig(, , .typ)
.variadic = true
.recordBuiltinType(.Fun, )
}
.mode = value
.typ =
break
}
= append(, *)
}
}
:= makeSig(, , NewSlice())
.variadic = true
var []*operand
for := range {
= append(, &[])
}
for := len(); < ; ++ {
var operand
(&, )
= append(, &)
}
.arguments(, , nil, , nil)
.mode = value
.typ =
if .Types != nil {
.recordBuiltinType(.Fun, )
}
case _Cap, _Len:
:= invalid
var constant.Value
switch t := arrayPtrDeref(under(.typ)).(type) {
case *Basic:
if isString() && == _Len {
if .mode == constant_ {
= constant_
= constant.MakeInt64(int64(len(constant.StringVal(.val))))
} else {
= value
}
}
case *Array:
= value
if !.hasCallOrRecv {
= constant_
if .len >= 0 {
= constant.MakeInt64(.len)
} else {
= constant.MakeUnknown()
}
}
case *Slice, *Chan:
= value
case *Map:
if == _Len {
= value
}
case *Interface:
if !isTypeParam(.typ) {
break
}
if .typeSet().underIs(func( Type) bool {
switch t := arrayPtrDeref().(type) {
case *Basic:
if isString() && == _Len {
return true
}
case *Array, *Slice, *Chan:
return true
case *Map:
if == _Len {
return true
}
}
return false
}) {
= value
}
}
if == invalid && under(.typ) != Typ[Invalid] {
:= _InvalidCap
if == _Len {
= _InvalidLen
}
.invalidArg(, , "%s for %s", , .name)
return
}
if .Types != nil && != constant_ {
.recordBuiltinType(.Fun, makeSig(Typ[Int], .typ))
}
.mode =
.typ = Typ[Int]
.val =
case _Close:
if !underIs(.typ, func( Type) bool {
, := .(*Chan)
if == nil {
.invalidOp(, _InvalidClose, "cannot close non-channel %s", )
return false
}
if .dir == RecvOnly {
.invalidOp(, _InvalidClose, "cannot close receive-only channel %s", )
return false
}
return true
}) {
return
}
.mode = novalue
if .Types != nil {
.recordBuiltinType(.Fun, makeSig(nil, .typ))
}
case _Complex:
var operand
(&, 1)
if .mode == invalid {
return
}
:= 0
if isUntyped(.typ) {
|= 1
}
if isUntyped(.typ) {
|= 2
}
switch {
case 0:
case 1:
.convertUntyped(, .typ)
case 2:
.convertUntyped(&, .typ)
case 3:
if .mode == constant_ && .mode == constant_ {
:= func( *operand) {
if isNumeric(.typ) && constant.Sign(constant.Imag(.val)) == 0 {
.typ = Typ[UntypedFloat]
}
}
()
(&)
} else {
.convertUntyped(, Typ[Float64])
.convertUntyped(&, Typ[Float64])
}
}
if .mode == invalid || .mode == invalid {
return
}
if !Identical(.typ, .typ) {
.invalidArg(, _InvalidComplex, "mismatched types %s and %s", .typ, .typ)
return
}
:= func( Type) Type {
assert(!isTypeParam())
if , := under().(*Basic); != nil {
switch .kind {
case Float32:
return Typ[Complex64]
case Float64:
return Typ[Complex128]
case UntypedFloat:
return Typ[UntypedComplex]
}
}
return nil
}
:= .applyTypeFunc(, , )
if == nil {
.invalidArg(, _InvalidComplex, "arguments have type %s, expected floating-point", .typ)
return
}
if .mode == constant_ && .mode == constant_ {
.val = constant.BinaryOp(constant.ToFloat(.val), token.ADD, constant.MakeImag(constant.ToFloat(.val)))
} else {
.mode = value
}
if .Types != nil && .mode != constant_ {
.recordBuiltinType(.Fun, makeSig(, .typ, .typ))
}
.typ =
case _Copy:
, := coreType(.typ).(*Slice)
var operand
(&, 1)
if .mode == invalid {
return
}
:= coreString(.typ)
if != nil && isString() {
= NewSlice(universeByte)
}
, := .(*Slice)
if == nil || == nil {
.invalidArg(, _InvalidCopy, "copy expects slice arguments; found %s and %s", , &)
return
}
if !Identical(.elem, .elem) {
.errorf(, _InvalidCopy, "arguments to copy %s and %s have different element types %s and %s", , &, .elem, .elem)
return
}
if .Types != nil {
.recordBuiltinType(.Fun, makeSig(Typ[Int], .typ, .typ))
}
.mode = value
.typ = Typ[Int]
case _Delete:
:= .typ
var Type
if !underIs(, func( Type) bool {
, := .(*Map)
if == nil {
.invalidArg(, _InvalidDelete, "%s is not a map", )
return false
}
if != nil && !Identical(.key, ) {
.invalidArg(, _InvalidDelete, "maps of %s must have identical key types", )
return false
}
= .key
return true
}) {
return
}
(, 1)
if .mode == invalid {
return
}
.assignment(, , "argument to delete")
if .mode == invalid {
return
}
.mode = novalue
if .Types != nil {
.recordBuiltinType(.Fun, makeSig(nil, , ))
}
case _Imag, _Real:
if isUntyped(.typ) {
if .mode == constant_ {
if isNumeric(.typ) {
.typ = Typ[UntypedComplex]
}
} else {
.convertUntyped(, Typ[Complex128])
if .mode == invalid {
return
}
}
}
:= func( Type) Type {
assert(!isTypeParam())
if , := under().(*Basic); != nil {
switch .kind {
case Complex64:
return Typ[Float32]
case Complex128:
return Typ[Float64]
case UntypedComplex:
return Typ[UntypedFloat]
}
}
return nil
}
:= .applyTypeFunc(, , )
if == nil {
:= _InvalidImag
if == _Real {
= _InvalidReal
}
.invalidArg(, , "argument has type %s, expected complex type", .typ)
return
}
if .mode == constant_ {
if == _Real {
.val = constant.Real(.val)
} else {
.val = constant.Imag(.val)
}
} else {
.mode = value
}
if .Types != nil && .mode != constant_ {
.recordBuiltinType(.Fun, makeSig(, .typ))
}
.typ =
case _Make:
:= .Args[0]
:= .varType()
if == Typ[Invalid] {
return
}
var int
switch coreType().(type) {
case *Slice:
= 2
case *Map, *Chan:
= 1
case nil:
.errorf(, _InvalidMake, "cannot make %s: no core type", )
return
default:
.invalidArg(, _InvalidMake, "cannot make %s; type must be slice, map, or channel", )
return
}
if < || +1 < {
.invalidOp(, _WrongArgCount, "%v expects %d or %d arguments; found %d", , , +1, )
return
}
:= []Type{}
var []int64
for , := range .Args[1:] {
, := .index(, -1)
= append(, )
if >= 0 {
= append(, )
}
}
if len() == 2 && [0] > [1] {
.invalidArg(.Args[1], _SwappedMakeArgs, "length and capacity swapped")
}
.mode = value
.typ =
if .Types != nil {
.recordBuiltinType(.Fun, makeSig(.typ, ...))
}
case _New:
:= .varType(.Args[0])
if == Typ[Invalid] {
return
}
.mode = value
.typ = &Pointer{base: }
if .Types != nil {
.recordBuiltinType(.Fun, makeSig(.typ, ))
}
case _Panic:
if .sig != nil && .sig.results.Len() > 0 {
:= .isPanic
if == nil {
= make(map[*ast.CallExpr]bool)
.isPanic =
}
[] = true
}
.assignment(, &emptyInterface, "argument to panic")
if .mode == invalid {
return
}
.mode = novalue
if .Types != nil {
.recordBuiltinType(.Fun, makeSig(nil, &emptyInterface))
}
case _Print, _Println:
var []Type
if > 0 {
= make([]Type, )
for := 0; < ; ++ {
if > 0 {
(, )
}
.assignment(, nil, "argument to "+predeclaredFuncs[].name)
if .mode == invalid {
return
}
[] = .typ
}
}
.mode = novalue
if .Types != nil {
.recordBuiltinType(.Fun, makeSig(nil, ...))
}
case _Recover:
.mode = value
.typ = &emptyInterface
if .Types != nil {
.recordBuiltinType(.Fun, makeSig(.typ))
}
case _Add:
if !.allowVersion(.pkg, 1, 17) {
.errorf(.Fun, _InvalidUnsafeAdd, "unsafe.Add requires go1.17 or later")
return
}
.assignment(, Typ[UnsafePointer], "argument to unsafe.Add")
if .mode == invalid {
return
}
var operand
(&, 1)
if !.isValidIndex(&, _InvalidUnsafeAdd, "length", true) {
return
}
.mode = value
.typ = Typ[UnsafePointer]
if .Types != nil {
.recordBuiltinType(.Fun, makeSig(.typ, .typ, .typ))
}
case _Alignof:
.assignment(, nil, "argument to unsafe.Alignof")
if .mode == invalid {
return
}
if hasVarSize(.typ) {
.mode = value
if .Types != nil {
.recordBuiltinType(.Fun, makeSig(Typ[Uintptr], .typ))
}
} else {
.mode = constant_
.val = constant.MakeInt64(.conf.alignof(.typ))
}
.typ = Typ[Uintptr]
case _Offsetof:
:= .Args[0]
, := unparen().(*ast.SelectorExpr)
if == nil {
.invalidArg(, _BadOffsetofSyntax, "%s is not a selector expression", )
.use()
return
}
.expr(, .X)
if .mode == invalid {
return
}
:= derefStructPtr(.typ)
:= .Sel.Name
, , := LookupFieldOrMethod(, false, .pkg, )
switch .(type) {
case nil:
.invalidArg(, _MissingFieldOrMethod, "%s has no single field %s", , )
return
case *Func:
.invalidArg(, _InvalidOffsetof, "%s is a method value", )
return
}
if {
.invalidArg(, _InvalidOffsetof, "field %s is embedded via a pointer in %s", , )
return
}
.recordSelection(, FieldVal, , , , false)
{
:= value
if .mode == variable || {
= variable
}
.record(&operand{, , .Type(), nil, 0})
}
if hasVarSize() {
.mode = value
if .Types != nil {
.recordBuiltinType(.Fun, makeSig(Typ[Uintptr], .Type()))
}
} else {
.mode = constant_
.val = constant.MakeInt64(.conf.offsetof(, ))
}
.typ = Typ[Uintptr]
case _Sizeof:
.assignment(, nil, "argument to unsafe.Sizeof")
if .mode == invalid {
return
}
if hasVarSize(.typ) {
.mode = value
if .Types != nil {
.recordBuiltinType(.Fun, makeSig(Typ[Uintptr], .typ))
}
} else {
.mode = constant_
.val = constant.MakeInt64(.conf.sizeof(.typ))
}
.typ = Typ[Uintptr]
case _Slice:
if !.allowVersion(.pkg, 1, 17) {
.errorf(.Fun, _InvalidUnsafeSlice, "unsafe.Slice requires go1.17 or later")
return
}
, := under(.typ).(*Pointer)
if == nil {
.invalidArg(, _InvalidUnsafeSlice, "%s is not a pointer", )
return
}
var operand
(&, 1)
if !.isValidIndex(&, _InvalidUnsafeSlice, "length", false) {
return
}
.mode = value
.typ = NewSlice(.base)
if .Types != nil {
.recordBuiltinType(.Fun, makeSig(.typ, , .typ))
}
case _Assert:
if .mode != constant_ || !isBoolean(.typ) {
.invalidArg(, _Test, "%s is not a boolean constant", )
return
}
if .val.Kind() != constant.Bool {
.errorf(, _Test, "internal error: value of %s should be a boolean constant", )
return
}
if !constant.BoolVal(.val) {
.errorf(, _Test, "%v failed", )
}
case _Trace:
if == 0 {
.dump("%v: trace() without arguments", .Pos())
.mode = novalue
break
}
var operand
:=
for , := range .Args {
.rawExpr(, , nil, false)
.dump("%v: %s", .Pos(), )
= &
}
default:
unreachable()
}
return true
}
func ( Type) bool {
switch u := under().(type) {
case *Array:
return (.elem)
case *Struct:
for , := range .fields {
if (.typ) {
return true
}
}
case *Interface:
return isTypeParam()
case *Named, *Union:
unreachable()
}
return false
}
func ( *Checker) ( func(Type) Type, *operand, builtinId) Type {
if , := .typ.(*TypeParam); != nil {
var []*Term
if !.is(func( *term) bool {
if == nil {
return false
}
if := (.typ); != nil {
= append(, NewTerm(.tilde, ))
return true
}
return false
}) {
return nil
}
var errorCode
switch {
case _Real:
= _InvalidReal
case _Imag:
= _InvalidImag
case _Complex:
= _InvalidComplex
default:
unreachable()
}
.softErrorf(, , "%s not supported as argument to %s for go1.18 (see issue #50937)", , predeclaredFuncs[].name)
:= NewTypeName(token.NoPos, .pkg, .obj.name, nil)
:= .newTypeParam(, NewInterfaceType(nil, []Type{NewUnion()}))
.index = .index
return
}
return (.typ)
}
func ( Type, ...Type) *Signature {
:= make([]*Var, len())
for , := range {
[] = NewVar(token.NoPos, nil, "", Default())
}
:= NewTuple(...)
var *Tuple
if != nil {
assert(!isUntyped())
= NewTuple(NewVar(token.NoPos, nil, "", ))
}
return &Signature{params: , results: }
}
func ( Type) Type {
if , := .(*Pointer); {
if , := under(.base).(*Array); != nil {
return
}
}
return
}
func ( ast.Expr) ast.Expr {
for {
, := .(*ast.ParenExpr)
if ! {
return
}
= .X
}
}