if x.mode == invalid {
return
}
- if isString(x.typ) {
+ if allString(x.typ) {
if check.Types != nil {
sig := makeSig(S, S, x.typ)
sig.variadic = true
var val constant.Value
switch typ = arrayPtrDeref(under(x.typ)); t := typ.(type) {
case *Basic:
- if isString(t) && id == _Len {
+ if is_String(t) && id == _Len {
if x.mode == constant_ {
mode = constant_
val = constant.MakeInt64(int64(len(constant.StringVal(x.val))))
if t.underIs(func(t Type) bool {
switch t := arrayPtrDeref(t).(type) {
case *Basic:
- if isString(t) && id == _Len {
+ if is_String(t) && id == _Len {
return true
}
case *Array, *Slice, *Chan:
// because shifts of floats are not permitted)
if x.mode == constant_ && y.mode == constant_ {
toFloat := func(x *operand) {
- if isNumeric(x.typ) && constant.Sign(constant.Imag(x.val)) == 0 {
+ if is_Numeric(x.typ) && constant.Sign(constant.Imag(x.val)) == 0 {
x.typ = Typ[UntypedFloat]
}
}
if x.mode == constant_ {
// an untyped constant number can always be considered
// as a complex constant
- if isNumeric(x.typ) {
+ if is_Numeric(x.typ) {
x.typ = Typ[UntypedComplex]
}
} else {
// assert(pred) causes a typechecker error if pred is false.
// The result of assert is the value of pred if there is no error.
// Note: assert is only available in self-test mode.
- if x.mode != constant_ || !isBoolean(x.typ) {
+ if x.mode != constant_ || !is_Boolean(x.typ) {
check.invalidArg(x, _Test, "%s is not a boolean constant", x)
return
}
func structureString(typ Type) Type {
var su Type
if underIs(typ, func(u Type) bool {
- if isString(u) {
+ if is_String(u) {
u = NewSlice(universeByte)
}
if su != nil && !Identical(su, u) {
}
if mode == constant_ {
assert(val != nil)
- // We check is(typ, IsConstType) here as constant expressions may be
+ // We check allBasic(typ, IsConstType) here as constant expressions may be
// recorded as type parameters.
- assert(typ == Typ[Invalid] || is(typ, IsConstType))
+ assert(typ == Typ[Invalid] || allBasic(typ, IsConstType))
}
if m := check.Types; m != nil {
m[x] = TypeAndValue{mode, typ, val}
if a[0] == nil || a[1] == nil {
return
}
- assert(isTyped(a[0]) && isTyped(a[1]) && (isBoolean(a[1]) || a[1] == universeError))
+ assert(isTyped(a[0]) && isTyped(a[1]) && (is_Boolean(a[1]) || a[1] == universeError))
if m := check.Types; m != nil {
for {
tv := m[x]
// nothing to do
case representableConst(x.val, check, t, val):
return true
- case isInteger(x.typ) && isString(t):
+ case is_Integer(x.typ) && is_String(t):
codepoint := unicode.ReplacementChar
if i, ok := constant.Uint64Val(x.val); ok && i <= unicode.MaxRune {
codepoint = rune(i)
// (See also the TODO below.)
if IsInterface(T) || constArg && !isConstType(T) || x.isNil() {
final = Default(x.typ) // default type of untyped nil is untyped nil
- } else if isInteger(x.typ) && isString(T) {
+ } else if is_Integer(x.typ) && allString(T) {
final = x.typ
}
check.updateExprType(x.expr, final, true)
}
// "V and T are both integer or floating point types"
- if isIntegerOrFloat(V) && isIntegerOrFloat(T) {
+ if is_IntegerOrFloat(V) && is_IntegerOrFloat(T) {
return true
}
// "V and T are both complex types"
- if isComplex(V) && isComplex(T) {
+ if is_Complex(V) && is_Complex(T) {
return true
}
// "V is an integer or a slice of bytes or runes and T is a string type"
- if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) {
+ if (is_Integer(V) || isBytesOrRunes(Vu)) && is_String(T) {
return true
}
// "V is a string and T is a slice of bytes or runes"
- if isString(V) && isBytesOrRunes(Tu) {
+ if is_String(V) && isBytesOrRunes(Tu) {
return true
}
func init() {
// Setting unaryOpPredicates in init avoids declaration cycles.
unaryOpPredicates = opPredicates{
- token.ADD: isNumeric,
- token.SUB: isNumeric,
- token.XOR: isInteger,
- token.NOT: isBoolean,
+ token.ADD: allNumeric,
+ token.SUB: allNumeric,
+ token.XOR: allInteger,
+ token.NOT: allBoolean,
}
}
return
}
var prec uint
- if isUnsigned(x.typ) {
+ if is_Unsigned(x.typ) {
prec = uint(check.conf.sizeof(x.typ) * 8)
}
x.val = constant.UnaryOp(e.Op, x.val, prec)
}
switch {
- case isInteger(typ):
+ case is_Integer(typ):
x := constant.ToInt(x)
if x.Kind() != constant.Int {
return false
return true
}
- case isFloat(typ):
+ case is_Float(typ):
x := constant.ToFloat(x)
if x.Kind() != constant.Float {
return false
unreachable()
}
- case isComplex(typ):
+ case is_Complex(typ):
x := constant.ToComplex(x)
if x.Kind() != constant.Complex {
return false
unreachable()
}
- case isString(typ):
+ case is_String(typ):
return x.Kind() == constant.String
- case isBoolean(typ):
+ case is_Boolean(typ):
return x.Kind() == constant.Bool
}
assert(x.mode == constant_)
v := x.val
if !representableConst(x.val, check, typ, &v) {
- if isNumeric(x.typ) && isNumeric(typ) {
+ if is_Numeric(x.typ) && is_Numeric(typ) {
// numeric conversion : error msg
//
// integer -> integer : overflows
// float -> integer : truncated
// float -> float : overflows
//
- if !isInteger(x.typ) && isInteger(typ) {
+ if !is_Integer(x.typ) && is_Integer(typ) {
return nil, _TruncatedFloat
} else {
return nil, _NumericOverflow
// If x is the lhs of a shift, its final type must be integer.
// We already know from the shift check that it is representable
// as an integer if it is a constant.
- if !isInteger(typ) {
+ if !is_Integer(typ) {
check.invalidOp(x, _InvalidShiftOperand, "shifted operand %s (type %s) must be integer", x, typ)
return
}
// both x and target are untyped
xkind := x.typ.(*Basic).kind
tkind := target.(*Basic).kind
- if isNumeric(x.typ) && isNumeric(target) {
+ if is_Numeric(x.typ) && is_Numeric(target) {
if xkind < tkind {
return target, nil, 0
}
return x.typ, nil, 0
}
- switch t := under(target).(type) {
+ switch u := under(target).(type) {
case *Basic:
if x.mode == constant_ {
- v, code := check.representation(x, t)
+ v, code := check.representation(x, u)
if code != 0 {
return nil, nil, code
}
// the value nil.
switch x.typ.(*Basic).kind {
case UntypedBool:
- if !isBoolean(target) {
+ if !is_Boolean(target) {
return nil, nil, _InvalidUntypedConversion
}
case UntypedInt, UntypedRune, UntypedFloat, UntypedComplex:
- if !isNumeric(target) {
+ if !is_Numeric(target) {
return nil, nil, _InvalidUntypedConversion
}
case UntypedString:
// Non-constant untyped string values are not permitted by the spec and
// should not occur during normal typechecking passes, but this path is
// reachable via the AssignableTo API.
- if !isString(target) {
+ if !is_String(target) {
return nil, nil, _InvalidUntypedConversion
}
case UntypedNil:
}
case *TypeParam:
// TODO(gri) review this code - doesn't look quite right
- ok := t.underIs(func(t Type) bool {
+ ok := u.underIs(func(t Type) bool {
target, _, _ := check.implicitTypeAndValue(x, t)
return target != nil
})
return Typ[UntypedNil], nil, 0
}
// cannot assign untyped values to non-empty interfaces
- if !t.Empty() {
+ if !u.Empty() {
return nil, nil, _InvalidUntypedConversion
}
return Default(x.typ), nil, 0
defined = Comparable(x.typ) && Comparable(y.typ) || x.isNil() && hasNil(y.typ) || y.isNil() && hasNil(x.typ)
case token.LSS, token.LEQ, token.GTR, token.GEQ:
// spec: The ordering operators <, <=, >, and >= apply to operands that are ordered."
- defined = isOrdered(x.typ) && isOrdered(y.typ)
+ defined = allOrdered(x.typ) && allOrdered(y.typ)
default:
unreachable()
}
xval = constant.ToInt(x.val)
}
- if isInteger(x.typ) || isUntyped(x.typ) && xval != nil && xval.Kind() == constant.Int {
+ if allInteger(x.typ) || isUntyped(x.typ) && xval != nil && xval.Kind() == constant.Int {
// The lhs is of integer type or an untyped constant representable
// as an integer. Nothing to do.
} else {
if isUntyped(y.typ) {
// Caution: Check for representability here, rather than in the switch
- // below, because isInteger includes untyped integers (was bug #43697).
+ // below, because is_Integer includes untyped integers (was bug #43697).
check.representable(y, Typ[Uint])
if y.mode == invalid {
x.mode = invalid
// Check that RHS is otherwise at least of integer type.
switch {
- case isInteger(y.typ):
- if !isUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) {
+ case allInteger(y.typ):
+ if !allUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) {
check.invalidOp(y, _InvalidShiftCount, "signed shift count %s requires go1.13 or later", y)
x.mode = invalid
return
if x.val.Kind() == constant.Unknown || y.val.Kind() == constant.Unknown {
x.val = constant.MakeUnknown()
// ensure the correct type - see comment below
- if !isInteger(x.typ) {
+ if !is_Integer(x.typ) {
x.typ = Typ[UntypedInt]
}
return
// (e.g., 2.0, an untyped float) - this can only happen for untyped
// non-integer numeric constants. Correct the type so that the shift
// result is of integer type.
- if !isInteger(x.typ) {
+ if !is_Integer(x.typ) {
x.typ = Typ[UntypedInt]
}
// x is a constant so xval != nil and it must be of Int kind.
}
// non-constant shift - lhs must be an integer
- if !isInteger(x.typ) {
+ if !allInteger(x.typ) {
check.invalidOp(x, _InvalidShiftOperand, "shifted operand %s must be integer", x)
x.mode = invalid
return
func init() {
// Setting binaryOpPredicates in init avoids declaration cycles.
binaryOpPredicates = opPredicates{
- token.ADD: isNumericOrString,
- token.SUB: isNumeric,
- token.MUL: isNumeric,
- token.QUO: isNumeric,
- token.REM: isInteger,
-
- token.AND: isInteger,
- token.OR: isInteger,
- token.XOR: isInteger,
- token.AND_NOT: isInteger,
-
- token.LAND: isBoolean,
- token.LOR: isBoolean,
+ 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,
}
}
if IsInterface(x.typ) || IsInterface(y.typ) {
return true
}
- if isBoolean(x.typ) != isBoolean(y.typ) {
+ if allBoolean(x.typ) != allBoolean(y.typ) {
return false
}
- if isString(x.typ) != isString(y.typ) {
+ if allString(x.typ) != allString(y.typ) {
return false
}
if x.isNil() && !hasNil(y.typ) {
if op == token.QUO || op == token.REM {
// check for zero divisor
- if (x.mode == constant_ || isInteger(x.typ)) && y.mode == constant_ && constant.Sign(y.val) == 0 {
+ if (x.mode == constant_ || allInteger(x.typ)) && y.mode == constant_ && constant.Sign(y.val) == 0 {
check.invalidOp(&y, _DivByZero, "division by zero")
x.mode = invalid
return
}
// check for divisor underflow in complex division (see issue 20227)
- if x.mode == constant_ && y.mode == constant_ && isComplex(x.typ) {
+ if x.mode == constant_ && y.mode == constant_ && is_Complex(x.typ) {
re, im := constant.Real(y.val), constant.Imag(y.val)
re2, im2 := constant.BinaryOp(re, token.MUL, re), constant.BinaryOp(im, token.MUL, im)
if constant.Sign(re2) == 0 && constant.Sign(im2) == 0 {
return
}
// force integer division of integer operands
- if op == token.QUO && isInteger(x.typ) {
+ if op == token.QUO && is_Integer(x.typ) {
op = token.QUO_ASSIGN
}
x.val = constant.BinaryOp(x.val, op, y.val)
return false
}
+ // ordinary index expression
valid := false
length := int64(-1) // valid if >= 0
switch typ := under(x.typ).(type) {
case *Basic:
- if isString(typ) {
+ if is_String(typ) {
valid = true
if x.mode == constant_ {
length = int64(len(constant.StringVal(x.val)))
var k, e Type // k is only set for maps
switch t := u.(type) {
case *Basic:
- if isString(t) {
+ if is_String(t) {
e = universeByte
mode = value
}
return
case *Basic:
- if isString(u) {
+ if is_String(u) {
if e.Slice3 {
check.invalidOp(x, _InvalidSliceExpr, "3-index slice of string")
x.mode = invalid
}
// spec: "the index x must be of integer type or an untyped constant"
- if !isInteger(x.typ) {
+ if !allInteger(x.typ) {
check.invalidArg(x, code, "%s %s must be integer", what, x)
return false
}
return named != nil && named.obj != nil && named.targs == nil && named.TypeParams() != nil
}
-func is(typ Type, what BasicInfo) bool {
- switch t := under(typ).(type) {
+// The is_X predicates below report whether t is an X.
+// If t is a type parameter the result is false; i.e.,
+// these predicates don't look inside a type parameter.
+
+func is_Boolean(t Type) bool { return isBasic(t, IsBoolean) }
+func is_Integer(t Type) bool { return isBasic(t, IsInteger) }
+func is_Unsigned(t Type) bool { return isBasic(t, IsUnsigned) }
+func is_Float(t Type) bool { return isBasic(t, IsFloat) }
+func is_Complex(t Type) bool { return isBasic(t, IsComplex) }
+func is_Numeric(t Type) bool { return isBasic(t, IsNumeric) }
+func is_String(t Type) bool { return isBasic(t, IsString) }
+func is_IntegerOrFloat(t Type) bool { return isBasic(t, IsInteger|IsFloat) }
+
+// isBasic reports whether under(t) is a basic type with the specified info.
+// If t is a type parameter the result is false; i.e.,
+// isBasic does not look inside a type parameter.
+func isBasic(t Type, info BasicInfo) bool {
+ u, _ := under(t).(*Basic)
+ return u != nil && u.info&info != 0
+}
+
+// The allX predicates below report whether t is an X.
+// If t is a type parameter the result is true if is_X is true
+// for all specified types of the type parameter's type set.
+// allX is an optimized version of is_X(structure(t)) (which
+// is the same as underIs(t, is_X)).
+
+func allBoolean(typ Type) bool { return allBasic(typ, IsBoolean) }
+func allInteger(typ Type) bool { return allBasic(typ, IsInteger) }
+func allUnsigned(typ Type) bool { return allBasic(typ, IsUnsigned) }
+func allNumeric(typ Type) bool { return allBasic(typ, IsNumeric) }
+func allString(typ Type) bool { return allBasic(typ, IsString) }
+func allOrdered(typ Type) bool { return allBasic(typ, IsOrdered) }
+func allNumericOrString(typ Type) bool { return allBasic(typ, IsNumeric|IsString) }
+
+// allBasic reports whether under(t) is a basic type with the specified info.
+// If t is a type parameter, the result is true if isBasic(t, info) is true
+// for all specific types of the type parameter's type set.
+// allBasic(t, info) is an optimized version of isBasic(structure(t), info).
+func allBasic(t Type, info BasicInfo) bool {
+ switch u := under(t).(type) {
case *Basic:
- return t.info&what != 0
+ return u.info&info != 0
case *TypeParam:
- return t.underIs(func(typ Type) bool { return is(typ, what) })
+ return u.is(func(t *term) bool { return t != nil && isBasic(t.typ, info) })
}
return false
}
-func isBoolean(typ Type) bool { return is(typ, IsBoolean) }
-func isInteger(typ Type) bool { return is(typ, IsInteger) }
-func isUnsigned(typ Type) bool { return is(typ, IsUnsigned) }
-func isFloat(typ Type) bool { return is(typ, IsFloat) }
-func isComplex(typ Type) bool { return is(typ, IsComplex) }
-func isNumeric(typ Type) bool { return is(typ, IsNumeric) }
-func isString(typ Type) bool { return is(typ, IsString) }
-
-// Note that if typ is a type parameter, isInteger(typ) || isFloat(typ) does not
-// produce the expected result because a type set that contains both an integer
-// and a floating-point type is neither (all) integers, nor (all) floats.
-// Use isIntegerOrFloat instead.
-func isIntegerOrFloat(typ Type) bool { return is(typ, IsInteger|IsFloat) }
-
-// isNumericOrString is the equivalent of isIntegerOrFloat for isNumeric(typ) || isString(typ).
-func isNumericOrString(typ Type) bool { return is(typ, IsNumeric|IsString) }
-
// isTyped reports whether typ is typed; i.e., not an untyped
// constant or boolean. isTyped may be called with types that
// are not fully set up.
return !isTyped(typ)
}
-func isOrdered(typ Type) bool { return is(typ, IsOrdered) }
-
func isConstType(typ Type) bool {
// Type parameters are never const types.
t := asBasic(typ)
return 1
}
// complex{64,128} are aligned like [2]float{32,64}.
- if isComplex(T) {
+ if is_Complex(T) {
a /= 2
}
if a > s.MaxAlign {
if x.mode == invalid {
return
}
- if !isNumeric(x.typ) {
+ if !allNumeric(x.typ) {
check.invalidOp(s.X, _NonNumericIncDec, "%s%s (non-numeric type %s)", s.X, s.Tok, x.typ)
return
}
check.simpleStmt(s.Init)
var x operand
check.expr(&x, s.Cond)
- if x.mode != invalid && !isBoolean(x.typ) {
+ if x.mode != invalid && !allBoolean(x.typ) {
check.error(s.Cond, _InvalidCond, "non-boolean condition in if statement")
}
check.stmt(inner, s.Body)
if s.Cond != nil {
var x operand
check.expr(&x, s.Cond)
- if x.mode != invalid && !isBoolean(x.typ) {
+ if x.mode != invalid && !allBoolean(x.typ) {
check.error(s.Cond, _InvalidCond, "non-boolean condition in for statement")
}
}
func rangeKeyVal(typ Type) (key, val Type) {
switch typ := arrayPtrDeref(typ).(type) {
case *Basic:
- if isString(typ) {
+ if is_String(typ) {
return Typ[Int], universeRune // use 'rune' name
}
case *Array:
return -1
}
- if isUntyped(x.typ) || isInteger(x.typ) {
+ if isUntyped(x.typ) || is_Integer(x.typ) {
if val := constant.ToInt(x.val); val.Kind() == constant.Int {
if representableConst(val, check, Typ[Int], nil) {
if n, ok := constant.Int64Val(val); ok && n >= 0 {