package types
import (
)
type opPredicates map[token.Token]func(Type) bool
var unaryOpPredicates opPredicates
func () {
unaryOpPredicates = opPredicates{
token.ADD: allNumeric,
token.SUB: allNumeric,
token.XOR: allInteger,
token.NOT: allBoolean,
}
}
func ( *Checker) ( opPredicates, *operand, token.Token) bool {
if := []; != nil {
if !(.typ) {
.invalidOp(, _UndefinedOp, "operator %s not defined on %s", , )
return false
}
} else {
.invalidAST(, "unknown operator %s", )
return false
}
return true
}
func ( *Checker) ( *operand, token.Token, token.Pos) {
assert(.mode == constant_)
if .val.Kind() == constant.Unknown {
.errorf(atPos(), _InvalidConstVal, "constant result is not representable")
return
}
if isTyped(.typ) {
.representable(, under(.typ).(*Basic))
return
}
const = 512
if .val.Kind() == constant.Int && constant.BitLen(.val) > {
.errorf(atPos(), _InvalidConstVal, "constant %s overflow", opName(.expr))
.val = constant.MakeUnknown()
}
}
func ( ast.Expr) string {
switch e := .(type) {
case *ast.BinaryExpr:
if int(.Op) < len(op2str2) {
return op2str2[.Op]
}
case *ast.UnaryExpr:
if int(.Op) < len(op2str1) {
return op2str1[.Op]
}
}
return ""
}
var op2str1 = [...]string{
token.XOR: "bitwise complement",
}
var op2str2 = [...]string{
token.ADD: "addition",
token.SUB: "subtraction",
token.XOR: "bitwise XOR",
token.MUL: "multiplication",
token.SHL: "shift",
}
func ( Type, func(Type) bool) bool {
if , := .(*TypeParam); != nil {
return .underIs()
}
return (under())
}
func ( *Checker) ( *operand, *ast.UnaryExpr) {
.expr(, .X)
if .mode == invalid {
return
}
switch .Op {
case token.AND:
if , := unparen(.X).(*ast.CompositeLit); ! && .mode != variable {
.invalidOp(, _UnaddressableOperand, "cannot take address of %s", )
.mode = invalid
return
}
.mode = value
.typ = &Pointer{base: .typ}
return
case token.ARROW:
:= coreType(.typ)
if == nil {
.invalidOp(, _InvalidReceive, "cannot receive from %s: no core type", )
.mode = invalid
return
}
, := .(*Chan)
if == nil {
.invalidOp(, _InvalidReceive, "cannot receive from non-channel %s", )
.mode = invalid
return
}
if .dir == SendOnly {
.invalidOp(, _InvalidReceive, "cannot receive from send-only channel %s", )
.mode = invalid
return
}
.mode = commaok
.typ = .elem
.hasCallOrRecv = true
return
}
if !.op(unaryOpPredicates, , .Op) {
.mode = invalid
return
}
if .mode == constant_ {
if .val.Kind() == constant.Unknown {
return
}
var uint
if isUnsigned(.typ) {
= uint(.conf.sizeof(.typ) * 8)
}
.val = constant.UnaryOp(.Op, .val, )
.expr =
.overflow(, .Op, .Pos())
return
}
.mode = value
}
func ( token.Token) bool {
return == token.SHL || == token.SHR
}
func ( token.Token) bool {
switch {
case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
return true
}
return false
}
func ( constant.Value) bool {
, := constant.Float32Val()
:= float64()
return !math.IsInf(, 0)
}
func ( constant.Value) constant.Value {
, := constant.Float32Val()
:= float64()
if !math.IsInf(, 0) {
return constant.MakeFloat64()
}
return nil
}
func ( constant.Value) bool {
, := constant.Float64Val()
return !math.IsInf(, 0)
}
func ( constant.Value) constant.Value {
, := constant.Float64Val()
if !math.IsInf(, 0) {
return constant.MakeFloat64()
}
return nil
}
func ( constant.Value, *Checker, *Basic, *constant.Value) bool {
if .Kind() == constant.Unknown {
return true
}
var *Config
if != nil {
= .conf
}
switch {
case isInteger():
:= constant.ToInt()
if .Kind() != constant.Int {
return false
}
if != nil {
* =
}
if , := constant.Int64Val(); {
switch .kind {
case Int:
var = uint(.sizeof()) * 8
return int64(-1)<<(-1) <= && <= int64(1)<<(-1)-1
case Int8:
const = 8
return -1<<(-1) <= && <= 1<<(-1)-1
case Int16:
const = 16
return -1<<(-1) <= && <= 1<<(-1)-1
case Int32:
const = 32
return -1<<(-1) <= && <= 1<<(-1)-1
case Int64, UntypedInt:
return true
case Uint, Uintptr:
if := uint(.sizeof()) * 8; < 64 {
return 0 <= && <= int64(1)<<-1
}
return 0 <=
case Uint8:
const = 8
return 0 <= && <= 1<<-1
case Uint16:
const = 16
return 0 <= && <= 1<<-1
case Uint32:
const = 32
return 0 <= && <= 1<<-1
case Uint64:
return 0 <=
default:
unreachable()
}
}
switch := constant.BitLen(); .kind {
case Uint, Uintptr:
var = uint(.sizeof()) * 8
return constant.Sign() >= 0 && <= int()
case Uint64:
return constant.Sign() >= 0 && <= 64
case UntypedInt:
return true
}
case isFloat():
:= constant.ToFloat()
if .Kind() != constant.Float {
return false
}
switch .kind {
case Float32:
if == nil {
return fitsFloat32()
}
:= roundFloat32()
if != nil {
* =
return true
}
case Float64:
if == nil {
return fitsFloat64()
}
:= roundFloat64()
if != nil {
* =
return true
}
case UntypedFloat:
return true
default:
unreachable()
}
case isComplex():
:= constant.ToComplex()
if .Kind() != constant.Complex {
return false
}
switch .kind {
case Complex64:
if == nil {
return fitsFloat32(constant.Real()) && fitsFloat32(constant.Imag())
}
:= roundFloat32(constant.Real())
:= roundFloat32(constant.Imag())
if != nil && != nil {
* = constant.BinaryOp(, token.ADD, constant.MakeImag())
return true
}
case Complex128:
if == nil {
return fitsFloat64(constant.Real()) && fitsFloat64(constant.Imag())
}
:= roundFloat64(constant.Real())
:= roundFloat64(constant.Imag())
if != nil && != nil {
* = constant.BinaryOp(, token.ADD, constant.MakeImag())
return true
}
case UntypedComplex:
return true
default:
unreachable()
}
case isString():
return .Kind() == constant.String
case isBoolean():
return .Kind() == constant.Bool
}
return false
}
func ( *Checker) ( *operand, *Basic) {
, := .representation(, )
if != 0 {
.invalidConversion(, , )
.mode = invalid
return
}
assert( != nil)
.val =
}
func ( *Checker) ( *operand, *Basic) (constant.Value, errorCode) {
assert(.mode == constant_)
:= .val
if !representableConst(.val, , , &) {
if isNumeric(.typ) && isNumeric() {
if !isInteger(.typ) && isInteger() {
return nil, _TruncatedFloat
} else {
return nil, _NumericOverflow
}
}
return nil, _InvalidConstVal
}
return , 0
}
func ( *Checker) ( errorCode, *operand, Type) {
:= "cannot convert %s to %s"
switch {
case _TruncatedFloat:
= "%s truncated to %s"
case _NumericOverflow:
= "%s overflows %s"
}
.errorf(, , , , )
}
func ( *Checker) ( ast.Expr, Type, bool) {
.updateExprType0(nil, , , )
}
func ( *Checker) (, ast.Expr, Type, bool) {
, := .untyped[]
if ! {
return
}
switch x := .(type) {
case *ast.BadExpr,
*ast.FuncLit,
*ast.CompositeLit,
*ast.IndexExpr,
*ast.SliceExpr,
*ast.TypeAssertExpr,
*ast.StarExpr,
*ast.KeyValueExpr,
*ast.ArrayType,
*ast.StructType,
*ast.FuncType,
*ast.InterfaceType,
*ast.MapType,
*ast.ChanType:
if debug {
.dump("%v: found old type(%s): %s (new: %s)", .Pos(), , .typ, )
unreachable()
}
return
case *ast.CallExpr:
case *ast.Ident, *ast.BasicLit, *ast.SelectorExpr:
case *ast.ParenExpr:
.(, .X, , )
case *ast.UnaryExpr:
if .val != nil {
break
}
.(, .X, , )
case *ast.BinaryExpr:
if .val != nil {
break
}
if isComparison(.Op) {
} else if isShift(.Op) {
.(, .X, , )
} else {
.(, .X, , )
.(, .Y, , )
}
default:
unreachable()
}
if ! && isUntyped() {
.typ = under().(*Basic)
.untyped[] =
return
}
delete(.untyped, )
if .isLhs {
if !allInteger() {
if compilerErrorMessages {
.invalidOp(, _InvalidShiftOperand, "%s (shift of type %s)", , )
} else {
.invalidOp(, _InvalidShiftOperand, "shifted operand %s (type %s) must be integer", , )
}
return
}
}
if .val != nil {
:= operand{.mode, , .typ, .val, 0}
.convertUntyped(&, )
if .mode == invalid {
return
}
}
.recordTypeAndValue(, .mode, , .val)
}
func ( *Checker) ( ast.Expr, constant.Value) {
if , := .untyped[]; {
.val =
.untyped[] =
}
}
func ( *Checker) ( *operand, Type) {
, , := .implicitTypeAndValue(, )
if != 0 {
:=
if !isTypeParam() {
= safeUnderlying()
}
.invalidConversion(, , )
.mode = invalid
return
}
if != nil {
.val =
.updateExprVal(.expr, )
}
if != .typ {
.typ =
.updateExprType(.expr, , false)
}
}
func ( *Checker) ( *operand, Type) (Type, constant.Value, errorCode) {
if .mode == invalid || isTyped(.typ) || == Typ[Invalid] {
return .typ, nil, 0
}
if isUntyped() {
:= .typ.(*Basic).kind
:= .(*Basic).kind
if isNumeric(.typ) && isNumeric() {
if < {
return , nil, 0
}
} else if != {
return nil, nil, _InvalidUntypedConversion
}
return .typ, nil, 0
}
switch u := under().(type) {
case *Basic:
if .mode == constant_ {
, := .representation(, )
if != 0 {
return nil, nil,
}
return , ,
}
switch .typ.(*Basic).kind {
case UntypedBool:
if !isBoolean() {
return nil, nil, _InvalidUntypedConversion
}
case UntypedInt, UntypedRune, UntypedFloat, UntypedComplex:
if !isNumeric() {
return nil, nil, _InvalidUntypedConversion
}
case UntypedString:
if !isString() {
return nil, nil, _InvalidUntypedConversion
}
case UntypedNil:
if !hasNil() {
return nil, nil, _InvalidUntypedConversion
}
return Typ[UntypedNil], nil, 0
default:
return nil, nil, _InvalidUntypedConversion
}
case *Interface:
if isTypeParam() {
if !.typeSet().underIs(func( Type) bool {
if == nil {
return false
}
, , := .(, )
return != nil
}) {
return nil, nil, _InvalidUntypedConversion
}
if .isNil() {
return Typ[UntypedNil], nil, 0
}
break
}
if .isNil() {
return Typ[UntypedNil], nil, 0
}
if !.Empty() {
return nil, nil, _InvalidUntypedConversion
}
return Default(.typ), nil, 0
case *Pointer, *Signature, *Slice, *Map, *Chan:
if !.isNil() {
return nil, nil, _InvalidUntypedConversion
}
return Typ[UntypedNil], nil, 0
default:
return nil, nil, _InvalidUntypedConversion
}
return , nil, 0
}
func ( *Checker) (, *operand, token.Token, bool) {
if {
= token.EQL
}
:=
:= ""
:= _MismatchedTypes
, := .assignableTo(, .typ, nil)
if ! {
, _ = .assignableTo(, .typ, nil)
}
if ! {
=
if !compilerErrorMessages {
=
}
= .sprintf("mismatched types %s and %s", .typ, .typ)
goto
}
= _UndefinedOp
switch {
case token.EQL, token.NEQ:
switch {
case .isNil() || .isNil():
:= .typ
if .isNil() {
= .typ
}
if !hasNil() {
=
goto
}
case !Comparable(.typ):
=
= .incomparableCause(.typ)
goto
case !Comparable(.typ):
=
= .incomparableCause(.typ)
goto
}
case token.LSS, token.LEQ, token.GTR, token.GEQ:
switch {
case !allOrdered(.typ):
=
goto
case !allOrdered(.typ):
=
goto
}
default:
unreachable()
}
if .mode == constant_ && .mode == constant_ {
.val = constant.MakeBool(constant.Compare(.val, , .val))
} else {
.mode = value
.updateExprType(.expr, Default(.typ), true)
.updateExprType(.expr, Default(.typ), true)
}
.typ = Typ[UntypedBool]
return
:
if == "" {
if isTypeParam(.typ) || isTypeParam(.typ) {
if !isTypeParam(.typ) {
=
}
= .sprintf("type parameter %s is not comparable with %s", .typ, )
} else {
= .sprintf("operator %s not defined on %s", , .kindString(.typ))
}
}
if {
.errorf(, , "invalid case %s in switch on %s (%s)", .expr, .expr, )
} else {
if compilerErrorMessages {
.invalidOp(, , "%s %s %s (%s)", .expr, , .expr, )
} else {
.invalidOp(, , "cannot compare %s %s %s (%s)", .expr, , .expr, )
}
}
.mode = invalid
}
func ( *Checker) ( Type) string {
switch under().(type) {
case *Slice, *Signature, *Map:
return .kindString() + " can only be compared to nil"
}
var string
comparable(, true, nil, func( string, ...interface{}) {
= .sprintf(, ...)
})
return
}
func ( *Checker) ( Type) string {
switch under().(type) {
case *Array:
return "array"
case *Slice:
return "slice"
case *Struct:
return "struct"
case *Pointer:
return "pointer"
case *Signature:
return "func"
case *Interface:
if isTypeParam() {
return .sprintf("type parameter %s", )
}
return "interface"
case *Map:
return "map"
case *Chan:
return "chan"
default:
return .sprintf("%s", )
}
}
func ( *Checker) (, *operand, ast.Expr, token.Token) {
var constant.Value
if .mode == constant_ {
= constant.ToInt(.val)
}
if allInteger(.typ) || isUntyped(.typ) && != nil && .Kind() == constant.Int {
} else {
.invalidOp(, _InvalidShiftOperand, "shifted operand %s must be integer", )
.mode = invalid
return
}
if .mode == constant_ {
:= constant.ToInt(.val)
if .Kind() == constant.Int && constant.Sign() < 0 {
.invalidOp(, _InvalidShiftCount, "negative shift count %s", )
.mode = invalid
return
}
if isUntyped(.typ) {
.representable(, Typ[Uint])
if .mode == invalid {
.mode = invalid
return
}
}
} else {
switch {
case allInteger(.typ):
if !allUnsigned(.typ) && !.allowVersion(.pkg, 1, 13) {
.invalidOp(, _InvalidShiftCount, "signed shift count %s requires go1.13 or later", )
.mode = invalid
return
}
case isUntyped(.typ):
.convertUntyped(, Typ[Uint])
if .mode == invalid {
.mode = invalid
return
}
default:
.invalidOp(, _InvalidShiftCount, "shift count %s must be integer", )
.mode = invalid
return
}
}
if .mode == constant_ {
if .mode == constant_ {
if .val.Kind() == constant.Unknown || .val.Kind() == constant.Unknown {
.val = constant.MakeUnknown()
if !isInteger(.typ) {
.typ = Typ[UntypedInt]
}
return
}
const = 1023 - 1 + 52
, := constant.Uint64Val(.val)
if ! || > {
.invalidOp(, _InvalidShiftCount, "invalid shift count %s", )
.mode = invalid
return
}
if !isInteger(.typ) {
.typ = Typ[UntypedInt]
}
.val = constant.Shift(, , uint())
.expr =
:= .Pos()
if , := .(*ast.BinaryExpr); != nil {
= .OpPos
}
.overflow(, , )
return
}
if isUntyped(.typ) {
if , := .untyped[.expr]; {
.isLhs = true
.untyped[.expr] =
}
.mode = value
return
}
}
if !allInteger(.typ) {
.invalidOp(, _InvalidShiftOperand, "shifted operand %s must be integer", )
.mode = invalid
return
}
.mode = value
}
var binaryOpPredicates opPredicates
func () {
binaryOpPredicates = opPredicates{
token.ADD: allNumericOrString,
token.SUB: allNumeric,
token.MUL: allNumeric,
token.QUO: allNumeric,
token.REM: allInteger,
token.AND: allInteger,
token.OR: allInteger,
token.XOR: allInteger,
token.AND_NOT: allInteger,
token.LAND: allBoolean,
token.LOR: allBoolean,
}
}
func ( *Checker) ( *operand, ast.Expr, , ast.Expr, token.Token, token.Pos) {
var operand
.expr(, )
.expr(&, )
if .mode == invalid {
return
}
if .mode == invalid {
.mode = invalid
.expr = .expr
return
}
if isShift() {
.shift(, &, , )
return
}
:= func(, *operand) bool {
if IsInterface(.typ) && !isTypeParam(.typ) || IsInterface(.typ) && !isTypeParam(.typ) {
return true
}
if allBoolean(.typ) != allBoolean(.typ) {
return false
}
if allString(.typ) != allString(.typ) {
return false
}
if .isNil() && !hasNil(.typ) {
return false
}
if .isNil() && !hasNil(.typ) {
return false
}
return true
}
if (, &) {
.convertUntyped(, .typ)
if .mode == invalid {
return
}
.convertUntyped(&, .typ)
if .mode == invalid {
.mode = invalid
return
}
}
if isComparison() {
.comparison(, &, , false)
return
}
if !Identical(.typ, .typ) {
if .typ != Typ[Invalid] && .typ != Typ[Invalid] {
var positioner =
if != nil {
=
}
if != nil {
.invalidOp(, _MismatchedTypes, "%s (mismatched types %s and %s)", , .typ, .typ)
} else {
.invalidOp(, _MismatchedTypes, "%s %s= %s (mismatched types %s and %s)", , , , .typ, .typ)
}
}
.mode = invalid
return
}
if !.op(binaryOpPredicates, , ) {
.mode = invalid
return
}
if == token.QUO || == token.REM {
if (.mode == constant_ || allInteger(.typ)) && .mode == constant_ && constant.Sign(.val) == 0 {
.invalidOp(&, _DivByZero, "division by zero")
.mode = invalid
return
}
if .mode == constant_ && .mode == constant_ && isComplex(.typ) {
, := constant.Real(.val), constant.Imag(.val)
, := constant.BinaryOp(, token.MUL, ), constant.BinaryOp(, token.MUL, )
if constant.Sign() == 0 && constant.Sign() == 0 {
.invalidOp(&, _DivByZero, "division by zero")
.mode = invalid
return
}
}
}
if .mode == constant_ && .mode == constant_ {
if .val.Kind() == constant.Unknown || .val.Kind() == constant.Unknown {
.val = constant.MakeUnknown()
return
}
if == token.QUO && isInteger(.typ) {
= token.QUO_ASSIGN
}
.val = constant.BinaryOp(.val, , .val)
.expr =
.overflow(, , )
return
}
.mode = value
}
type exprKind int
const (
conversion exprKind = iota
expression
statement
)
func ( *Checker) ( *operand, ast.Expr, Type, bool) exprKind {
if trace {
.trace(.Pos(), "expr %s", )
.indent++
defer func() {
.indent--
.trace(.Pos(), "=> %s", )
}()
}
:= .exprInternal(, , )
if ! {
.nonGeneric()
}
.record()
return
}
func ( *Checker) ( *operand) {
if .mode == invalid || .mode == novalue {
return
}
var string
switch t := .typ.(type) {
case *Named:
if isGeneric() {
= "type"
}
case *Signature:
if .tparams != nil {
= "function"
}
}
if != "" {
.errorf(.expr, _WrongTypeArgCount, "cannot use generic %s %s without instantiation", , .expr)
.mode = invalid
.typ = Typ[Invalid]
}
}
func ( *Checker) ( *operand, ast.Expr, Type) exprKind {
.mode = invalid
.typ = Typ[Invalid]
switch e := .(type) {
case *ast.BadExpr:
goto
case *ast.Ident:
.ident(, , nil, false)
case *ast.Ellipsis:
.error(, _BadDotDotDotSyntax, "invalid use of '...'")
goto
case *ast.BasicLit:
switch .Kind {
case token.INT, token.FLOAT, token.IMAG:
.langCompat()
const = 10000
if len(.Value) > {
.errorf(, _InvalidConstVal, "excessively long constant: %s... (%d chars)", .Value[:10], len(.Value))
goto
}
}
.setConst(.Kind, .Value)
if .mode == invalid {
.errorf(, _InvalidConstVal, "malformed constant: %s", .Value)
goto
}
case *ast.FuncLit:
if , := .typ(.Type).(*Signature); {
if !.conf.IgnoreFuncBodies && .Body != nil {
:= .decl
:= .iota
.later(func() {
.funcBody(, "<function literal>", , .Body, )
})
}
.mode = value
.typ =
} else {
.invalidAST(, "invalid function literal %s", )
goto
}
case *ast.CompositeLit:
var , Type
switch {
case .Type != nil:
if , := .Type.(*ast.ArrayType); != nil && .Len != nil {
if , := .Len.(*ast.Ellipsis); != nil && .Elt == nil {
= &Array{len: -1, elem: .varType(.Elt)}
=
break
}
}
= .typ(.Type)
=
case != nil:
=
, _ = deref(coreType())
if == nil {
.errorf(, _InvalidLit, "invalid composite literal element type %s: no core type", )
goto
}
default:
.error(, _UntypedLit, "missing type in composite literal")
goto
}
switch utyp := coreType().(type) {
case *Struct:
if .fields == nil {
.error(, _InvalidDeclCycle, "illegal cycle in type declaration")
goto
}
if len(.Elts) == 0 {
break
}
:= .fields
if , := .Elts[0].(*ast.KeyValueExpr); {
:= make([]bool, len())
for , := range .Elts {
, := .(*ast.KeyValueExpr)
if == nil {
.error(, _MixedStructLit, "mixture of field:value and value elements in struct literal")
continue
}
, := .Key.(*ast.Ident)
.expr(, .Value)
if == nil {
.errorf(, _InvalidLitField, "invalid field name %s in struct literal", .Key)
continue
}
:= fieldIndex(.fields, .pkg, .Name)
if < 0 {
.errorf(, _MissingLitField, "unknown field %s in struct literal", .Name)
continue
}
:= []
.recordUse(, )
:= .typ
.assignment(, , "struct literal")
if [] {
.errorf(, _DuplicateLitField, "duplicate field name %s in struct literal", .Name)
continue
}
[] = true
}
} else {
for , := range .Elts {
if , := .(*ast.KeyValueExpr); != nil {
.error(, _MixedStructLit, "mixture of field:value and value elements in struct literal")
continue
}
.expr(, )
if >= len() {
.error(, _InvalidStructLit, "too many values in struct literal")
break
}
:= []
if !.Exported() && .pkg != .pkg {
.errorf(,
_UnexportedLitField,
"implicit assignment to unexported field %s in %s literal", .name, )
continue
}
:= .typ
.assignment(, , "struct literal")
}
if len(.Elts) < len() {
.error(inNode(, .Rbrace), _InvalidStructLit, "too few values in struct literal")
}
}
case *Array:
if .elem == nil {
.error(, _InvalidTypeCycle, "illegal cycle in type declaration")
goto
}
:= .indexedElts(.Elts, .elem, .len)
if .len < 0 {
.len =
if .Type != nil {
.recordTypeAndValue(.Type, typexpr, , nil)
}
}
case *Slice:
if .elem == nil {
.error(, _InvalidTypeCycle, "illegal cycle in type declaration")
goto
}
.indexedElts(.Elts, .elem, -1)
case *Map:
if .key == nil || .elem == nil {
.error(, _InvalidTypeCycle, "illegal cycle in type declaration")
goto
}
:= make(map[any][]Type, len(.Elts))
for , := range .Elts {
, := .(*ast.KeyValueExpr)
if == nil {
.error(, _MissingLitKey, "missing key in map literal")
continue
}
.exprWithHint(, .Key, .key)
.assignment(, .key, "map literal")
if .mode == invalid {
continue
}
if .mode == constant_ {
:= false
:= keyVal(.val)
if IsInterface(.key) {
for , := range [] {
if Identical(, .typ) {
= true
break
}
}
[] = append([], .typ)
} else {
_, = []
[] = nil
}
if {
.errorf(, _DuplicateLitKey, "duplicate key %s in map literal", .val)
continue
}
}
.exprWithHint(, .Value, .elem)
.assignment(, .elem, "map literal")
}
default:
for , := range .Elts {
if , := .(*ast.KeyValueExpr); != nil {
= .Value
}
.use()
}
if != Typ[Invalid] {
.errorf(, _InvalidLit, "invalid composite literal type %s", )
goto
}
}
.mode = value
.typ =
case *ast.ParenExpr:
:= .rawExpr(, .X, nil, false)
.expr =
return
case *ast.SelectorExpr:
.selector(, , nil)
case *ast.IndexExpr, *ast.IndexListExpr:
:= typeparams.UnpackIndexExpr()
if .indexExpr(, ) {
.funcInst(, )
}
if .mode == invalid {
goto
}
case *ast.SliceExpr:
.sliceExpr(, )
if .mode == invalid {
goto
}
case *ast.TypeAssertExpr:
.expr(, .X)
if .mode == invalid {
goto
}
if isTypeParam(.typ) {
.invalidOp(, _InvalidAssert, "cannot use type assertion on type parameter value %s", )
goto
}
if , := under(.typ).(*Interface); ! {
.invalidOp(, _InvalidAssert, "%s is not an interface", )
goto
}
if .Type == nil {
.error(, _BadTypeKeyword, "use of .(type) outside type switch")
goto
}
:= .varType(.Type)
if == Typ[Invalid] {
goto
}
.typeAssertion(, , , false)
.mode = commaok
.typ =
case *ast.CallExpr:
return .callExpr(, )
case *ast.StarExpr:
.exprOrType(, .X, false)
switch .mode {
case invalid:
goto
case typexpr:
.validVarType(.X, .typ)
.typ = &Pointer{base: .typ}
default:
var Type
if !underIs(.typ, func( Type) bool {
, := .(*Pointer)
if == nil {
.invalidOp(, _InvalidIndirection, "cannot indirect %s", )
return false
}
if != nil && !Identical(.base, ) {
.invalidOp(, _InvalidIndirection, "pointers of %s must have identical base types", )
return false
}
= .base
return true
}) {
goto
}
.mode = variable
.typ =
}
case *ast.UnaryExpr:
.unary(, )
if .mode == invalid {
goto
}
if .Op == token.ARROW {
.expr =
return statement
}
case *ast.BinaryExpr:
.binary(, , .X, .Y, .Op, .OpPos)
if .mode == invalid {
goto
}
case *ast.KeyValueExpr:
.invalidAST(, "no key:value expected")
goto
case *ast.ArrayType, *ast.StructType, *ast.FuncType,
*ast.InterfaceType, *ast.MapType, *ast.ChanType:
.mode = typexpr
.typ = .typ()
default:
panic(fmt.Sprintf("%s: unknown expression type %T", .fset.Position(.Pos()), ))
}
.expr =
return expression
:
.mode = invalid
.expr =
return statement
}
func ( constant.Value) any {
switch .Kind() {
case constant.Bool:
return constant.BoolVal()
case constant.String:
return constant.StringVal()
case constant.Int:
if , := constant.Int64Val(); {
return
}
if , := constant.Uint64Val(); {
return
}
case constant.Float:
, := constant.Float64Val()
return
case constant.Complex:
, := constant.Float64Val(constant.Real())
, := constant.Float64Val(constant.Imag())
return complex(, )
}
return
}
func ( *Checker) ( ast.Expr, *operand, Type, bool) {
, := .assertableTo(under(.typ).(*Interface), )
if == nil {
return
}
:= .missingMethodReason(, .typ, , )
if {
.errorf(, _ImpossibleAssert, "impossible type switch case: %s\n\t%s cannot have dynamic type %s %s", , , , )
return
}
.errorf(, _ImpossibleAssert, "impossible type assertion: %s\n\t%s does not implement %s %s", , , .typ, )
}
func ( *Checker) ( *operand, ast.Expr) {
.rawExpr(, , nil, false)
.exclude(, 1<<novalue|1<<builtin|1<<typexpr)
.singleValue()
}
func ( *Checker) ( *operand, ast.Expr) {
.rawExpr(, , nil, false)
.exclude(, 1<<novalue|1<<builtin|1<<typexpr)
}
func ( *Checker) ( *operand, ast.Expr, Type) {
assert( != nil)
.rawExpr(, , , false)
.exclude(, 1<<novalue|1<<builtin|1<<typexpr)
.singleValue()
}
func ( *Checker) ( *operand, ast.Expr, bool) {
.rawExpr(, , nil, )
.exclude(, 1<<novalue)
.singleValue()
}
func ( *Checker) ( *operand, uint) {
if &(1<<.mode) != 0 {
var string
var errorCode
switch .mode {
case novalue:
if &(1<<typexpr) != 0 {
= "%s used as value"
} else {
= "%s used as value or type"
}
= _TooManyValues
case builtin:
= "%s must be called"
= _UncalledBuiltin
case typexpr:
= "%s is not an expression"
= _NotAnExpr
default:
unreachable()
}
.errorf(, , , )
.mode = invalid
}
}
func ( *Checker) ( *operand) {
if .mode == value {
if , := .typ.(*Tuple); {
assert(.Len() != 1)
if compilerErrorMessages {
.errorf(, _TooManyValues, "multiple-value %s in single-value context", )
} else {
.errorf(, _TooManyValues, "%d-valued %s where single value is expected", .Len(), )
}
.mode = invalid
}
}
}