func (check *Checker) assignment(x *operand, T Type, context string) {
check.singleValue(x)
- switch x.mode_ {
+ switch x.mode() {
case invalid:
return // error reported before
case nilvalue:
}
func (check *Checker) initConst(lhs *Const, x *operand) {
- if x.mode_ == invalid || !isValid(x.typ()) || !isValid(lhs.typ) {
+ if x.mode() == invalid || !isValid(x.typ()) || !isValid(lhs.typ) {
if lhs.typ == nil {
lhs.typ = Typ[Invalid]
}
}
// rhs must be a constant
- if x.mode_ != constant_ {
+ if x.mode() != constant_ {
check.errorf(x, InvalidConstInit, "%s is not constant", x)
if lhs.typ == nil {
lhs.typ = Typ[Invalid]
}
check.assignment(x, lhs.typ, "constant declaration")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
// or Typ[Invalid] in case of an error.
// If the initialization check fails, x.mode is set to invalid.
func (check *Checker) initVar(lhs *Var, x *operand, context string) {
- if x.mode_ == invalid || !isValid(x.typ()) || !isValid(lhs.typ) {
+ if x.mode() == invalid || !isValid(x.typ()) || !isValid(lhs.typ) {
if lhs.typ == nil {
lhs.typ = Typ[Invalid]
}
check.usedVars[v] = v_used // restore v.used
}
- if x.mode_ == invalid || !isValid(x.typ()) {
+ if x.mode() == invalid || !isValid(x.typ()) {
return Typ[Invalid]
}
// spec: "Each left-hand side operand must be addressable, a map index
// expression, or the blank identifier. Operands may be parenthesized."
- switch x.mode_ {
+ switch x.mode() {
case invalid:
return Typ[Invalid]
case variable, mapindex:
if sel, ok := x.expr.(*syntax.SelectorExpr); ok {
var op operand
check.expr(nil, &op, sel.X)
- if op.mode_ == mapindex {
+ if op.mode() == mapindex {
check.errorf(&x, UnaddressableFieldAssign, "cannot assign to struct field %s in map", ExprString(x.expr))
return Typ[Invalid]
}
}
// Only record comma-ok expression if both initializations succeeded
// (go.dev/issue/59371).
- if commaOk && rhs[0].mode_ != invalid && rhs[1].mode_ != invalid {
+ if commaOk && rhs[0].mode() != invalid && rhs[1].mode() != invalid {
check.recordCommaOkTypes(orig_rhs[0], rhs)
}
return
// In all other cases we have an assignment mismatch.
// Only report a mismatch error if there are no other errors on the rhs.
- if rhs[0].mode_ != invalid {
+ if rhs[0].mode() != invalid {
if returnStmt != nil {
check.returnError(returnStmt, lhs, rhs)
} else {
}
// Only record comma-ok expression if both assignments succeeded
// (go.dev/issue/59371).
- if commaOk && rhs[0].mode_ != invalid && rhs[1].mode_ != invalid {
+ if commaOk && rhs[0].mode() != invalid && rhs[1].mode() != invalid {
check.recordCommaOkTypes(orig_rhs[0], rhs)
}
return
// In all other cases we have an assignment mismatch.
// Only report a mismatch error if there are no other errors on the rhs.
- if rhs[0].mode_ != invalid {
+ if rhs[0].mode() != invalid {
check.assignError(orig_rhs, l, r)
}
check.useLHS(lhs...)
args = check.exprList(argList)
nargs = len(args)
for _, a := range args {
- if a.mode_ == invalid {
+ if a.mode() == invalid {
return
}
}
switch t := arrayPtrDeref(x.typ().Underlying()).(type) {
case *Basic:
if isString(t) && id == _Len {
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
mode = constant_
val = constant.MakeInt64(int64(len(constant.StringVal(x.val))))
} else {
// both of them to float64 since they must have the
// same type to succeed (this will result in an error
// because shifts of floats are not permitted)
- if x.mode_ == constant_ && y.mode_ == constant_ {
+ if x.mode() == constant_ && y.mode() == constant_ {
toFloat := func(x *operand) {
if isNumeric(x.typ()) && constant.Sign(constant.Imag(x.val)) == 0 {
x.typ_ = Typ[UntypedFloat]
// and check below
}
}
- if x.mode_ == invalid || y.mode_ == invalid {
+ if x.mode() == invalid || y.mode() == invalid {
return
}
}
// if both arguments are constants, the result is a constant
- if x.mode_ == constant_ && y.mode_ == constant_ {
+ if x.mode() == constant_ && y.mode() == constant_ {
x.val = constant.BinaryOp(constant.ToFloat(x.val), token.ADD, constant.MakeImag(constant.ToFloat(y.val)))
} else {
x.mode_ = value
}
- if check.recordTypes() && x.mode_ != constant_ {
+ if check.recordTypes() && x.mode() != constant_ {
check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ(), x.typ()))
}
*x = *args[1] // key
check.assignment(x, key, "argument to delete")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
// convert or check untyped argument
if isUntyped(x.typ()) {
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
// an untyped constant number can always be considered
// as a complex constant
if isNumeric(x.typ()) {
// result in an error (shift of complex value)
check.convertUntyped(x, Typ[Complex128])
// x should be invalid now, but be conservative and check
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
}
}
// if the argument is a constant, the result is a constant
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
if id == _Real {
x.val = constant.Real(x.val)
} else {
x.mode_ = value
}
- if check.recordTypes() && x.mode_ != constant_ {
+ if check.recordTypes() && x.mode() != constant_ {
check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ()))
}
}
for i, a := range args {
- if a.mode_ == invalid {
+ if a.mode() == invalid {
return
}
// The first argument is already in x and there's nothing left to do.
if i > 0 {
check.matchTypes(x, a)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
return
}
- if x.mode_ == constant_ && a.mode_ == constant_ {
+ if x.mode() == constant_ && a.mode() == constant_ {
if constant.Compare(a.val, op, x.val) {
*x = *a
}
}
// If nargs == 1, make sure x.mode is either a value or a constant.
- if x.mode_ != constant_ {
+ if x.mode() != constant_ {
x.mode_ = value
// A value must not be untyped.
check.assignment(x, &emptyInterface, "argument to built-in "+bin.name)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
}
check.updateExprType(a.expr, x.typ(), true)
}
- if check.recordTypes() && x.mode_ != constant_ {
+ if check.recordTypes() && x.mode() != constant_ {
types := make([]Type, nargs)
for i := range types {
types[i] = x.typ()
arg := argList[0]
check.exprOrType(x, arg, false)
check.exclude(x, 1<<novalue|1<<builtin)
- switch x.mode_ {
+ switch x.mode() {
case invalid:
return
case typexpr:
if isUntyped(x.typ()) {
// check for overflow and untyped nil
check.assignment(x, nil, "argument to new")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
assert(isTyped(x.typ()))
}
check.assignment(x, &emptyInterface, "argument to panic")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
params = make([]Type, nargs)
for i, a := range args {
check.assignment(a, nil, "argument to built-in "+predeclaredFuncs[id].name)
- if a.mode_ == invalid {
+ if a.mode() == invalid {
return
}
params[i] = a.typ()
check.verifyVersionf(call.Fun, go1_17, "unsafe.Add")
check.assignment(x, Typ[UnsafePointer], "argument to unsafe.Add")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
case _Alignof:
// unsafe.Alignof(x T) uintptr
check.assignment(x, nil, "argument to unsafe.Alignof")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
}
check.expr(nil, x, selx.X)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
// record the selector expression (was bug - go.dev/issue/47895)
{
mode := value
- if x.mode_ == variable || indirect {
+ if x.mode() == variable || indirect {
mode = variable
}
check.record(&operand{mode, selx, obj.Type(), nil, 0})
case _Sizeof:
// unsafe.Sizeof(x T) uintptr
check.assignment(x, nil, "argument to unsafe.Sizeof")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
check.verifyVersionf(call.Fun, go1_20, "unsafe.String")
check.assignment(x, NewPointer(universeByte), "argument to unsafe.String")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
check.verifyVersionf(call.Fun, go1_20, "unsafe.StringData")
check.assignment(x, Typ[String], "argument to unsafe.StringData")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
// 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_ || !isBoolean(x.typ()) {
check.errorf(x, Test, invalidArg+"%s is not a boolean constant", x)
return
}
check.dump("%v: %s", atPos(x1), x1)
x1 = &t // use incoming x only for first argument
}
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
// trace is only available in test mode - no need to record signature
panic("unreachable")
}
- assert(x.mode_ != invalid)
+ assert(x.mode() != invalid)
return true
}
// Delay function instantiation to argument checking,
// where we combine type and value arguments for type
// inference.
- assert(x.mode_ == value)
+ assert(x.mode() == value)
inst = iexpr
}
x.expr = iexpr
}
// x.typ may be generic
- switch x.mode_ {
+ switch x.mode() {
case invalid:
check.use(call.ArgList...)
x.expr = call
case typexpr:
// conversion
check.nonGeneric(nil, x)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return conversion
}
T := x.typ()
check.errorf(call, WrongArgCount, "missing argument in conversion to %s", T)
case 1:
check.expr(nil, x, call.ArgList[0])
- if x.mode_ != invalid {
+ if x.mode() != invalid {
if t, _ := T.Underlying().(*Interface); t != nil && !isTypeParam(T) {
if !t.IsMethodSet() {
check.errorf(call, MisplacedConstraintIface, "cannot use interface %s in conversion (contains specific type constraints or is comparable)", T)
}
x.expr = call
// a non-constant result implies a function call
- if x.mode_ != invalid && x.mode_ != constant_ {
+ if x.mode() != invalid && x.mode() != constant_ {
check.hasCallOrRecv = true
}
return predeclaredFuncs[id].kind
// ordinary function/method call
// signature may be generic
- cgocall := x.mode_ == cgofunc
+ cgocall := x.mode() == cgofunc
// If the operand type is a type parameter, all types in its type set
// must have a common underlying type, which must be a signature.
// if type inference failed, a parameterized result must be invalidated
// (operands cannot have a parameterized type)
- if x.mode_ == value && sig.TypeParams().Len() > 0 && isParameterized(sig.TypeParams().list(), x.typ()) {
+ if x.mode() == value && sig.TypeParams().Len() > 0 && isParameterized(sig.TypeParams().list(), x.typ()) {
x.mode_ = invalid
}
// x is not a function instantiation (it may still be a generic function).
check.rawExpr(nil, &x, e, nil, true)
check.exclude(&x, 1<<novalue|1<<builtin|1<<typexpr)
- if t, ok := x.typ().(*Tuple); ok && x.mode_ != invalid {
+ if t, ok := x.typ().(*Tuple); ok && x.mode() != invalid {
// x is a function call returning multiple values; it cannot be generic.
resList = make([]*operand, t.Len())
for i, v := range t.vars {
}
check.exprOrType(x, e.X, false)
- switch x.mode_ {
+ switch x.mode() {
case builtin:
check.errorf(e.Pos(), UncalledBuiltin, "invalid use of %s in selector expression", x)
goto Error
goto Error
}
- obj, index, indirect = lookupFieldOrMethod(x.typ(), x.mode_ == variable, check.pkg, sel, false)
+ obj, index, indirect = lookupFieldOrMethod(x.typ(), x.mode() == variable, check.pkg, sel, false)
if obj == nil {
// Don't report another error if the underlying type was invalid (go.dev/issue/49541).
if !isValid(x.typ().Underlying()) {
}
if indirect {
- if x.mode_ == typexpr {
+ if x.mode() == typexpr {
check.errorf(e.Sel, InvalidMethodExpr, "invalid method expression %s.%s (needs pointer receiver (*%s).%s)", x.typ(), sel, x.typ(), sel)
} else {
check.errorf(e.Sel, InvalidMethodExpr, "cannot call pointer method %s on %s", sel, x.typ())
if isInterfacePtr(x.typ()) {
why = check.interfacePtrError(x.typ())
} else {
- alt, _, _ := lookupFieldOrMethod(x.typ(), x.mode_ == variable, check.pkg, sel, true)
+ alt, _, _ := lookupFieldOrMethod(x.typ(), x.mode() == variable, check.pkg, sel, true)
why = check.lookupError(x.typ(), sel, alt, false)
}
check.errorf(e.Sel, MissingFieldOrMethod, "%s.%s undefined (%s)", x.expr, sel, why)
switch obj := obj.(type) {
case *Var:
- if x.mode_ == typexpr {
+ if x.mode() == typexpr {
check.errorf(e.X, MissingFieldOrMethod, "operand for field selector %s must be value of type %s", sel, x.typ())
goto Error
}
// field value
check.recordSelection(e, FieldVal, x.typ(), obj, index, indirect)
- if x.mode_ == variable || indirect {
+ if x.mode() == variable || indirect {
x.mode_ = variable
} else {
x.mode_ = value
check.objDecl(obj) // ensure fully set-up signature
check.addDeclDep(obj)
- if x.mode_ == typexpr {
+ if x.mode() == typexpr {
// method expression
check.recordSelection(e, MethodExpr, x.typ(), obj, index, indirect)
default:
check.rawExpr(nil, &x, e, nil, true)
}
- return x.mode_ != invalid
+ return x.mode() != invalid
}
// For untyped constants, it checks that the value doesn't become
// arbitrarily large.
func (check *Checker) overflow(x *operand, opPos syntax.Pos) {
- assert(x.mode_ == constant_)
+ assert(x.mode() == constant_)
if x.val.Kind() == constant.Unknown {
// TODO(gri) We should report exactly what went wrong. At the
//
// If no such representation is possible, it returns a non-zero error code.
func (check *Checker) representation(x *operand, typ *Basic) (constant.Value, Code) {
- assert(x.mode_ == constant_)
+ assert(x.mode() == constant_)
v := x.val
if !representableConst(x.val, check, typ, &v) {
if isNumeric(x.typ()) && isNumeric(typ) {
// conversion type-checks the conversion T(x).
// The result is in x.
func (check *Checker) conversion(x *operand, T Type) {
- constArg := x.mode_ == constant_
+ constArg := x.mode() == constant_
constConvertibleTo := func(T Type, val *constant.Value) bool {
switch t, _ := T.Underlying().(*Basic); {
// ok
} else if isNonTypeParamInterface(T) || constArg && !isConstType(T) || !isTypes2 && x.isNil() {
final = Default(x.typ()) // default type of untyped nil is untyped nil
- } else if x.mode_ == constant_ && isInteger(x.typ()) && allString(T) {
+ } else if x.mode() == constant_ && isInteger(x.typ()) && allString(T) {
final = x.typ()
}
check.updateExprType(x.expr, final, true)
func (check *Checker) unary(x *operand, e *syntax.Operation) {
check.expr(nil, x, e.X)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
case syntax.And:
// spec: "As an exception to the addressability
// requirement x may also be a composite literal."
- if _, ok := syntax.Unparen(e.X).(*syntax.CompositeLit); !ok && x.mode_ != variable {
+ if _, ok := syntax.Unparen(e.X).(*syntax.CompositeLit); !ok && x.mode() != variable {
check.errorf(x, UnaddressableOperand, invalidOp+"cannot take address of %s", x)
x.mode_ = invalid
return
return
}
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
if x.val.Kind() == constant.Unknown {
// nothing to do (and don't cause an error below in the overflow check)
return
// If x is a constant, it must be representable as a value of typ.
c := operand{old.mode, x, old.typ, old.val, 0}
check.convertUntyped(&c, typ)
- if c.mode_ == invalid {
+ if c.mode() == invalid {
return
}
}
// If x is a constant operand, the returned constant.Value will be the
// representation of x in this context.
func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, constant.Value, Code) {
- if x.mode_ == invalid || isTyped(x.typ()) || !isValid(target) {
+ if x.mode() == invalid || isTyped(x.typ()) || !isValid(target) {
return x.typ(), nil, 0
}
// x is untyped
switch u := target.Underlying().(type) {
case *Basic:
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
v, code := check.representation(x, u)
if code != 0 {
return nil, nil, code
}
// comparison is ok
- if x.mode_ == constant_ && y.mode_ == constant_ {
+ if x.mode() == constant_ && y.mode() == constant_ {
x.val = constant.MakeBool(constant.Compare(x.val, op2tok[op], y.val))
// The operands are never materialized; no need to update
// their types.
// TODO(gri) This function seems overly complex. Revisit.
var xval constant.Value
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
xval = constant.ToInt(x.val)
}
// Check that constants are representable by uint, but do not convert them
// (see also go.dev/issue/47243).
var yval constant.Value
- if y.mode_ == constant_ {
+ if y.mode() == constant_ {
// Provide a good error message for negative shift counts.
yval = constant.ToInt(y.val) // consider -1, 1.0, but not -1.1
if yval.Kind() == constant.Int && constant.Sign(yval) < 0 {
// Caution: Check for representability here, rather than in the switch
// below, because isInteger includes untyped integers (was bug go.dev/issue/43697).
check.representable(y, Typ[Uint])
- if y.mode_ == invalid {
+ if y.mode() == invalid {
x.mode_ = invalid
return
}
// This is incorrect, but preserves pre-existing behavior.
// See also go.dev/issue/47410.
check.convertUntyped(y, Typ[Uint])
- if y.mode_ == invalid {
+ if y.mode() == invalid {
x.mode_ = invalid
return
}
}
}
- if x.mode_ == constant_ {
- if y.mode_ == constant_ {
+ if x.mode() == constant_ {
+ if y.mode() == constant_ {
// if either x or y has an unknown value, the result is unknown
if x.val.Kind() == constant.Unknown || y.val.Kind() == constant.Unknown {
x.val = constant.MakeUnknown()
check.expr(nil, x, lhs)
check.expr(nil, &y, rhs)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
- if y.mode_ == invalid {
+ if y.mode() == invalid {
x.mode_ = invalid
x.expr = y.expr
return
}
check.matchTypes(x, &y)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
if op == syntax.Div || op == syntax.Rem {
// check for zero divisor
- if (x.mode_ == constant_ || allInteger(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.error(&y, DivByZero, invalidOp+"division by zero")
x.mode_ = invalid
return
}
// check for divisor underflow in complex division (see go.dev/issue/20227)
- if x.mode_ == constant_ && y.mode_ == constant_ && isComplex(x.typ()) {
+ if x.mode() == constant_ && y.mode() == constant_ && isComplex(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 {
}
}
- if x.mode_ == constant_ && y.mode_ == constant_ {
+ if x.mode() == constant_ && y.mode() == constant_ {
// if either x or y has an unknown value, the result is unknown
if x.val.Kind() == constant.Unknown || y.val.Kind() == constant.Unknown {
x.val = constant.MakeUnknown()
if mayConvert(x, y) {
check.convertUntyped(x, y.typ())
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
check.convertUntyped(y, x.typ())
- if y.mode_ == invalid {
+ if y.mode() == invalid {
x.mode_ = invalid
return
}
// from a non-nil target T, nonGeneric reports an error and invalidates x.mode and x.typ.
// Otherwise it leaves x alone.
func (check *Checker) nonGeneric(T *target, x *operand) {
- if x.mode_ == invalid || x.mode_ == novalue {
+ if x.mode() == invalid || x.mode() == novalue {
return
}
var what string
goto Error // error reported during parsing
}
check.basicLit(x, e)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
goto Error
}
case *syntax.FuncLit:
check.funcLit(x, e)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
goto Error
}
case *syntax.CompositeLit:
check.compositeLit(x, e, hint)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
goto Error
}
}
check.funcInst(T, e.Pos(), x, e, true)
}
- if x.mode_ == invalid {
+ if x.mode() == invalid {
goto Error
}
case *syntax.SliceExpr:
check.sliceExpr(x, e)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
goto Error
}
case *syntax.AssertExpr:
check.expr(nil, x, e.X)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
goto Error
}
// x.(type) expressions are encoded via TypeSwitchGuards
if e.Op == syntax.Mul {
// pointer indirection
check.exprOrType(x, e.X, false)
- switch x.mode_ {
+ switch x.mode() {
case invalid:
goto Error
case typexpr:
}
check.unary(x, e)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
goto Error
}
if e.Op == syntax.Recv {
// binary expression
check.binary(x, e, e.X, e.Y, e.Op)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
goto Error
}
check.rawExpr(nil, &x, e, nil, false)
check.exclude(&x, 1<<novalue|1<<builtin|1<<typexpr)
- if t, ok := x.typ().(*Tuple); ok && x.mode_ != invalid {
+ if t, ok := x.typ().(*Tuple); ok && x.mode() != invalid {
// multiple values
list = make([]*operand, t.Len())
for i, v := range t.vars {
// exactly one (possibly invalid or comma-ok) value
list = []*operand{&x}
- if allowCommaOk && (x.mode_ == mapindex || x.mode_ == commaok || x.mode_ == commaerr) {
+ if allowCommaOk && (x.mode() == mapindex || x.mode() == commaok || x.mode() == commaerr) {
x2 := &operand{mode_: value, expr: e, typ_: Typ[UntypedBool]}
- if x.mode_ == commaerr {
+ if x.mode() == commaerr {
x2.typ_ = universeError
}
list = append(list, x2)
// exclude reports an error if x.mode is in modeset and sets x.mode to invalid.
// The modeset may contain any of 1<<novalue, 1<<builtin, 1<<typexpr.
func (check *Checker) exclude(x *operand, modeset uint) {
- if modeset&(1<<x.mode_) != 0 {
+ if modeset&(1<<x.mode()) != 0 {
var msg string
var code Code
- switch x.mode_ {
+ switch x.mode() {
case novalue:
if modeset&(1<<typexpr) != 0 {
msg = "%s used as value"
// singleValue reports an error if x describes a tuple and sets x.mode to invalid.
func (check *Checker) singleValue(x *operand) {
- if x.mode_ == value {
+ if x.mode() == value {
// tuple types are never named - no need for underlying type below
if t, ok := x.typ().(*Tuple); ok {
assert(t.Len() != 1)
check.exprOrType(x, e.X, true)
// x may be generic
- switch x.mode_ {
+ switch x.mode() {
case invalid:
check.use(e.Index)
return false
// x should not be generic at this point, but be safe and check
check.nonGeneric(nil, x)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return false
}
case *Basic:
if isString(typ) {
valid = true
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
length = int64(len(constant.StringVal(x.val)))
}
// an indexed string always yields a byte value
case *Array:
valid = true
length = typ.len
- if x.mode_ != variable {
+ if x.mode() != variable {
x.mode_ = value
}
x.typ_ = typ.elem
case *Array:
l = t.len
e = t.elem
- if x.mode_ != variable {
+ if x.mode() != variable {
mode = value
}
case *Pointer:
func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) {
check.expr(nil, x, e.X)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
check.use(e.Index[:]...)
return
}
return
}
valid = true
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
length = int64(len(constant.StringVal(x.val)))
}
// spec: "For untyped string operands the result
case *Array:
valid = true
length = u.len
- if x.mode_ != variable {
+ if x.mode() != variable {
check.errorf(x, NonSliceableOperand, "cannot slice unaddressable value %s", x)
x.mode_ = invalid
return
return
}
- if x.mode_ != constant_ {
+ if x.mode() != constant_ {
return x.typ(), -1
}
// If the operand is not valid, an error is reported (using what as context)
// and the result is false.
func (check *Checker) isValidIndex(x *operand, code Code, what string, allowNegative bool) bool {
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return false
}
// spec: "a constant index that is untyped is given type int"
check.convertUntyped(x, Typ[Int])
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return false
}
return false
}
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
// spec: "a constant index must be non-negative ..."
if !allowNegative && constant.Sign(x.val) < 0 {
check.errorf(x, code, invalidArg+"%s %s must not be negative", what, x)
// If we have invalid (ordinary) arguments, an error was reported before.
// Avoid additional inference errors and exit early (go.dev/issue/60434).
for _, arg := range args {
- if arg.mode_ == invalid {
+ if arg.mode() == invalid {
return nil
}
}
}
for i, arg := range args {
- if arg.mode_ == invalid {
+ if arg.mode() == invalid {
// An error was reported earlier. Ignore this arg
// and continue, we may still be able to infer all
// targs resulting in fewer follow-on errors.
}
}
x.setConst(e.Kind, e.Value)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
// The parser already establishes syntactic correctness.
// If we reach here it's because of number under-/overflow.
// TODO(gri) setConst (and in turn the go/constant package)
}
check.exprWithHint(x, kv.Key, utyp.key)
check.assignment(x, utyp.key, "map literal")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
continue
}
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
duplicate := false
xkey := keyVal(x.val)
if keyIsInterface {
id builtinId
}
+func (x *operand) mode() operandMode {
+ return x.mode_
+}
+
func (x *operand) typ() Type {
return x.typ_
}
func (x *operand) isValid() bool {
- return x.mode_ != invalid
+ return x.mode() != invalid
}
// Pos returns the position of the expression corresponding to x.
func operandString(x *operand, qf Qualifier) string {
// special-case nil
if isTypes2 {
- if x.mode_ == nilvalue {
+ if x.mode() == nilvalue {
switch x.typ() {
case nil, Typ[Invalid]:
return "nil (with invalid type)"
}
}
} else { // go/types
- if x.mode_ == value && x.typ() == Typ[UntypedNil] {
+ if x.mode() == value && x.typ() == Typ[UntypedNil] {
return "nil"
}
}
if x.expr != nil {
expr = ExprString(x.expr)
} else {
- switch x.mode_ {
+ switch x.mode() {
case builtin:
expr = predeclaredFuncs[x.id].name
case typexpr:
// <untyped kind>
hasType := false
- switch x.mode_ {
+ switch x.mode() {
case invalid, novalue, builtin, typexpr:
// no type
default:
}
// <mode>
- buf.WriteString(operandModeString[x.mode_])
+ buf.WriteString(operandModeString[x.mode()])
// <val>
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
if s := x.val.String(); s != expr {
buf.WriteByte(' ')
buf.WriteString(s)
// isNil reports whether x is the (untyped) nil value.
func (x *operand) isNil() bool {
if isTypes2 {
- return x.mode_ == nilvalue
+ return x.mode() == nilvalue
} else { // go/types
- return x.mode_ == value && x.typ() == Typ[UntypedNil]
+ return x.mode() == value && x.typ() == Typ[UntypedNil]
}
}
// if assignableTo is invoked through an exported API call, i.e., when all
// methods have been type-checked.
func (x *operand) assignableTo(check *Checker, T Type, cause *string) (bool, Code) {
- if x.mode_ == invalid || !isValid(T) {
+ if x.mode() == invalid || !isValid(T) {
return true, 0 // avoid spurious errors
}
check.hasCallOrRecv = false
check.expr(nil, &x, rangeVar)
- if isTypes2 && x.mode_ != invalid && sValue == nil && !check.hasCallOrRecv {
+ if isTypes2 && x.mode() != invalid && sValue == nil && !check.hasCallOrRecv {
if t, ok := arrayPtrDeref(x.typ().Underlying()).(*Array); ok {
for {
// Put constant info on the thing inside parentheses.
// determine key/value types
var key, val Type
- if x.mode_ != invalid {
+ if x.mode() != invalid {
k, v, cause, ok := rangeKeyVal(check, x.typ(), func(v goVersion) bool {
return check.allowVersion(v)
})
// If the assignment succeeded, if x was untyped before, it now
// has a type inferred via the assignment. It must be an integer.
// (go.dev/issues/67027)
- if x.mode_ != invalid && !isInteger(x.typ()) {
+ if x.mode() != invalid && !isInteger(x.typ()) {
check.softErrorf(lhs, InvalidRangeExpr, "cannot use iteration variable of type %s", x.typ())
}
} else {
// TODO(gri) this code can be simplified
var typ Type
var val constant.Value
- switch x.mode_ {
+ switch x.mode() {
case invalid:
typ = Typ[Invalid]
case novalue:
if isUntyped(typ) {
// delay type and value recording until we know the type
// or until the end of type checking
- check.rememberUntyped(x.expr, false, x.mode_, typ.(*Basic), val)
+ check.rememberUntyped(x.expr, false, x.mode(), typ.(*Basic), val)
} else {
- check.recordTypeAndValue(x.expr, x.mode_, typ, val)
+ check.recordTypeAndValue(x.expr, x.mode(), typ, val)
}
}
func (check *Checker) recordCommaOkTypes(x syntax.Expr, a []*operand) {
assert(x != nil)
assert(len(a) == 2)
- if a[0].mode_ == invalid {
+ if a[0].mode() == invalid {
return
}
t0, t1 := a[0].typ(), a[1].typ()
for _, e := range values {
var v operand
check.expr(nil, &v, e)
- if x.mode_ == invalid || v.mode_ == invalid {
+ if x.mode() == invalid || v.mode() == invalid {
continue L
}
check.convertUntyped(&v, x.typ())
- if v.mode_ == invalid {
+ if v.mode() == invalid {
continue L
}
// Order matters: By comparing v against x, error positions are at the case values.
res := v // keep original v unchanged
check.comparison(&res, x, syntax.Eql, true)
- if res.mode_ == invalid {
+ if res.mode() == invalid {
continue L
}
- if v.mode_ != constant_ {
+ if v.mode() != constant_ {
continue L // we're done
}
// look for duplicate values
kind := check.rawExpr(nil, &x, s.X, nil, false)
var msg string
var code Code
- switch x.mode_ {
+ switch x.mode() {
default:
if kind == statement {
return
var ch, val operand
check.expr(nil, &ch, s.Chan)
check.expr(nil, &val, s.Value)
- if ch.mode_ == invalid || val.mode_ == invalid {
+ if ch.mode() == invalid || val.mode() == invalid {
return
}
if elem := check.chanElem(s, &ch, false); elem != nil {
// (no need to call unpackExpr as s.Lhs must be single-valued)
var x operand
check.expr(nil, &x, s.Lhs)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
if !allNumeric(x.typ()) {
check.simpleStmt(s.Init)
var x operand
check.expr(nil, &x, s.Cond)
- if x.mode_ != invalid && !allBoolean(x.typ()) {
+ if x.mode() != invalid && !allBoolean(x.typ()) {
check.error(s.Cond, InvalidCond, "non-boolean condition in if statement")
}
check.stmt(inner, s.Then)
if s.Cond != nil {
var x operand
check.expr(nil, &x, s.Cond)
- if x.mode_ != invalid && !allBoolean(x.typ()) {
+ if x.mode() != invalid && !allBoolean(x.typ()) {
check.error(s.Cond, InvalidCond, "non-boolean condition in for statement")
}
}
// By checking assignment of x to an invisible temporary
// (as a compiler would), we get all the relevant checks.
check.assignment(&x, nil, "switch expression")
- if x.mode_ != invalid && !Comparable(x.typ()) && !hasNil(x.typ()) {
+ if x.mode() != invalid && !Comparable(x.typ()) && !hasNil(x.typ()) {
check.errorf(&x, InvalidExprSwitch, "cannot switch on %s (%s is not comparable)", &x, x.typ())
x.mode_ = invalid
}
{
var x operand
check.expr(nil, &x, guard.X)
- if x.mode_ != invalid {
+ if x.mode() != invalid {
if isTypeParam(x.typ()) {
check.errorf(&x, InvalidTypeSwitch, "cannot use type switch on type parameter value %s", &x)
} else if IsInterface(x.typ()) {
var x operand
check.ident(&x, e, true)
- switch x.mode_ {
+ switch x.mode() {
case typexpr:
return x.typ()
case invalid:
var x operand
check.selector(&x, e, true)
- switch x.mode_ {
+ switch x.mode() {
case typexpr:
return x.typ()
case invalid:
var x operand
check.expr(nil, &x, e)
- if x.mode_ != constant_ {
- if x.mode_ != invalid {
+ if x.mode() != constant_ {
+ if x.mode() != invalid {
check.errorf(&x, InvalidArrayLen, "array length %s must be constant", &x)
}
return -1
func (check *Checker) assignment(x *operand, T Type, context string) {
check.singleValue(x)
- switch x.mode_ {
+ switch x.mode() {
case invalid:
return // error reported before
case nilvalue:
}
func (check *Checker) initConst(lhs *Const, x *operand) {
- if x.mode_ == invalid || !isValid(x.typ()) || !isValid(lhs.typ) {
+ if x.mode() == invalid || !isValid(x.typ()) || !isValid(lhs.typ) {
if lhs.typ == nil {
lhs.typ = Typ[Invalid]
}
}
// rhs must be a constant
- if x.mode_ != constant_ {
+ if x.mode() != constant_ {
check.errorf(x, InvalidConstInit, "%s is not constant", x)
if lhs.typ == nil {
lhs.typ = Typ[Invalid]
}
check.assignment(x, lhs.typ, "constant declaration")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
// or Typ[Invalid] in case of an error.
// If the initialization check fails, x.mode is set to invalid.
func (check *Checker) initVar(lhs *Var, x *operand, context string) {
- if x.mode_ == invalid || !isValid(x.typ()) || !isValid(lhs.typ) {
+ if x.mode() == invalid || !isValid(x.typ()) || !isValid(lhs.typ) {
if lhs.typ == nil {
lhs.typ = Typ[Invalid]
}
check.usedVars[v] = v_used // restore v.used
}
- if x.mode_ == invalid || !isValid(x.typ()) {
+ if x.mode() == invalid || !isValid(x.typ()) {
return Typ[Invalid]
}
// spec: "Each left-hand side operand must be addressable, a map index
// expression, or the blank identifier. Operands may be parenthesized."
- switch x.mode_ {
+ switch x.mode() {
case invalid:
return Typ[Invalid]
case variable, mapindex:
if sel, ok := x.expr.(*ast.SelectorExpr); ok {
var op operand
check.expr(nil, &op, sel.X)
- if op.mode_ == mapindex {
+ if op.mode() == mapindex {
check.errorf(&x, UnaddressableFieldAssign, "cannot assign to struct field %s in map", ExprString(x.expr))
return Typ[Invalid]
}
}
// Only record comma-ok expression if both initializations succeeded
// (go.dev/issue/59371).
- if commaOk && rhs[0].mode_ != invalid && rhs[1].mode_ != invalid {
+ if commaOk && rhs[0].mode() != invalid && rhs[1].mode() != invalid {
check.recordCommaOkTypes(orig_rhs[0], rhs)
}
return
// In all other cases we have an assignment mismatch.
// Only report a mismatch error if there are no other errors on the rhs.
- if rhs[0].mode_ != invalid {
+ if rhs[0].mode() != invalid {
if returnStmt != nil {
check.returnError(returnStmt, lhs, rhs)
} else {
}
// Only record comma-ok expression if both assignments succeeded
// (go.dev/issue/59371).
- if commaOk && rhs[0].mode_ != invalid && rhs[1].mode_ != invalid {
+ if commaOk && rhs[0].mode() != invalid && rhs[1].mode() != invalid {
check.recordCommaOkTypes(orig_rhs[0], rhs)
}
return
// In all other cases we have an assignment mismatch.
// Only report a mismatch error if there are no other errors on the rhs.
- if rhs[0].mode_ != invalid {
+ if rhs[0].mode() != invalid {
check.assignError(orig_rhs, l, r)
}
check.useLHS(lhs...)
args = check.exprList(argList)
nargs = len(args)
for _, a := range args {
- if a.mode_ == invalid {
+ if a.mode() == invalid {
return
}
}
switch t := arrayPtrDeref(x.typ().Underlying()).(type) {
case *Basic:
if isString(t) && id == _Len {
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
mode = constant_
val = constant.MakeInt64(int64(len(constant.StringVal(x.val))))
} else {
// both of them to float64 since they must have the
// same type to succeed (this will result in an error
// because shifts of floats are not permitted)
- if x.mode_ == constant_ && y.mode_ == constant_ {
+ if x.mode() == constant_ && y.mode() == constant_ {
toFloat := func(x *operand) {
if isNumeric(x.typ()) && constant.Sign(constant.Imag(x.val)) == 0 {
x.typ_ = Typ[UntypedFloat]
// and check below
}
}
- if x.mode_ == invalid || y.mode_ == invalid {
+ if x.mode() == invalid || y.mode() == invalid {
return
}
}
// if both arguments are constants, the result is a constant
- if x.mode_ == constant_ && y.mode_ == constant_ {
+ if x.mode() == constant_ && y.mode() == constant_ {
x.val = constant.BinaryOp(constant.ToFloat(x.val), token.ADD, constant.MakeImag(constant.ToFloat(y.val)))
} else {
x.mode_ = value
}
- if check.recordTypes() && x.mode_ != constant_ {
+ if check.recordTypes() && x.mode() != constant_ {
check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ(), x.typ()))
}
*x = *args[1] // key
check.assignment(x, key, "argument to delete")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
// convert or check untyped argument
if isUntyped(x.typ()) {
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
// an untyped constant number can always be considered
// as a complex constant
if isNumeric(x.typ()) {
// result in an error (shift of complex value)
check.convertUntyped(x, Typ[Complex128])
// x should be invalid now, but be conservative and check
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
}
}
// if the argument is a constant, the result is a constant
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
if id == _Real {
x.val = constant.Real(x.val)
} else {
x.mode_ = value
}
- if check.recordTypes() && x.mode_ != constant_ {
+ if check.recordTypes() && x.mode() != constant_ {
check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ()))
}
}
for i, a := range args {
- if a.mode_ == invalid {
+ if a.mode() == invalid {
return
}
// The first argument is already in x and there's nothing left to do.
if i > 0 {
check.matchTypes(x, a)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
return
}
- if x.mode_ == constant_ && a.mode_ == constant_ {
+ if x.mode() == constant_ && a.mode() == constant_ {
if constant.Compare(a.val, op, x.val) {
*x = *a
}
}
// If nargs == 1, make sure x.mode is either a value or a constant.
- if x.mode_ != constant_ {
+ if x.mode() != constant_ {
x.mode_ = value
// A value must not be untyped.
check.assignment(x, &emptyInterface, "argument to built-in "+bin.name)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
}
check.updateExprType(a.expr, x.typ(), true)
}
- if check.recordTypes() && x.mode_ != constant_ {
+ if check.recordTypes() && x.mode() != constant_ {
types := make([]Type, nargs)
for i := range types {
types[i] = x.typ()
arg := argList[0]
check.exprOrType(x, arg, false)
check.exclude(x, 1<<novalue|1<<builtin)
- switch x.mode_ {
+ switch x.mode() {
case invalid:
return
case typexpr:
if isUntyped(x.typ()) {
// check for overflow and untyped nil
check.assignment(x, nil, "argument to new")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
assert(isTyped(x.typ()))
}
check.assignment(x, &emptyInterface, "argument to panic")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
params = make([]Type, nargs)
for i, a := range args {
check.assignment(a, nil, "argument to built-in "+predeclaredFuncs[id].name)
- if a.mode_ == invalid {
+ if a.mode() == invalid {
return
}
params[i] = a.typ()
check.verifyVersionf(call.Fun, go1_17, "unsafe.Add")
check.assignment(x, Typ[UnsafePointer], "argument to unsafe.Add")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
case _Alignof:
// unsafe.Alignof(x T) uintptr
check.assignment(x, nil, "argument to unsafe.Alignof")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
}
check.expr(nil, x, selx.X)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
// record the selector expression (was bug - go.dev/issue/47895)
{
mode := value
- if x.mode_ == variable || indirect {
+ if x.mode() == variable || indirect {
mode = variable
}
check.record(&operand{mode, selx, obj.Type(), nil, 0})
case _Sizeof:
// unsafe.Sizeof(x T) uintptr
check.assignment(x, nil, "argument to unsafe.Sizeof")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
check.verifyVersionf(call.Fun, go1_20, "unsafe.String")
check.assignment(x, NewPointer(universeByte), "argument to unsafe.String")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
check.verifyVersionf(call.Fun, go1_20, "unsafe.StringData")
check.assignment(x, Typ[String], "argument to unsafe.StringData")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
// 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_ || !isBoolean(x.typ()) {
check.errorf(x, Test, invalidArg+"%s is not a boolean constant", x)
return
}
check.dump("%v: %s", x1.Pos(), x1)
x1 = &t // use incoming x only for first argument
}
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
// trace is only available in test mode - no need to record signature
panic("unreachable")
}
- assert(x.mode_ != invalid)
+ assert(x.mode() != invalid)
return true
}
// Delay function instantiation to argument checking,
// where we combine type and value arguments for type
// inference.
- assert(x.mode_ == value)
+ assert(x.mode() == value)
} else {
ix = nil
}
}
// x.typ may be generic
- switch x.mode_ {
+ switch x.mode() {
case invalid:
check.use(call.Args...)
x.expr = call
case typexpr:
// conversion
check.nonGeneric(nil, x)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return conversion
}
T := x.typ()
check.errorf(inNode(call, call.Rparen), WrongArgCount, "missing argument in conversion to %s", T)
case 1:
check.expr(nil, x, call.Args[0])
- if x.mode_ != invalid {
+ if x.mode() != invalid {
if hasDots(call) {
check.errorf(call.Args[0], BadDotDotDotSyntax, "invalid use of ... in conversion to %s", T)
break
}
x.expr = call
// a non-constant result implies a function call
- if x.mode_ != invalid && x.mode_ != constant_ {
+ if x.mode() != invalid && x.mode() != constant_ {
check.hasCallOrRecv = true
}
return predeclaredFuncs[id].kind
// ordinary function/method call
// signature may be generic
- cgocall := x.mode_ == cgofunc
+ cgocall := x.mode() == cgofunc
// If the operand type is a type parameter, all types in its type set
// must have a common underlying type, which must be a signature.
// if type inference failed, a parameterized result must be invalidated
// (operands cannot have a parameterized type)
- if x.mode_ == value && sig.TypeParams().Len() > 0 && isParameterized(sig.TypeParams().list(), x.typ()) {
+ if x.mode() == value && sig.TypeParams().Len() > 0 && isParameterized(sig.TypeParams().list(), x.typ()) {
x.mode_ = invalid
}
// x is not a function instantiation (it may still be a generic function).
check.rawExpr(nil, &x, e, nil, true)
check.exclude(&x, 1<<novalue|1<<builtin|1<<typexpr)
- if t, ok := x.typ().(*Tuple); ok && x.mode_ != invalid {
+ if t, ok := x.typ().(*Tuple); ok && x.mode() != invalid {
// x is a function call returning multiple values; it cannot be generic.
resList = make([]*operand, t.Len())
for i, v := range t.vars {
}
check.exprOrType(x, e.X, false)
- switch x.mode_ {
+ switch x.mode() {
case builtin:
// types2 uses the position of '.' for the error
check.errorf(e.Sel, UncalledBuiltin, "invalid use of %s in selector expression", x)
goto Error
}
- obj, index, indirect = lookupFieldOrMethod(x.typ(), x.mode_ == variable, check.pkg, sel, false)
+ obj, index, indirect = lookupFieldOrMethod(x.typ(), x.mode() == variable, check.pkg, sel, false)
if obj == nil {
// Don't report another error if the underlying type was invalid (go.dev/issue/49541).
if !isValid(x.typ().Underlying()) {
}
if indirect {
- if x.mode_ == typexpr {
+ if x.mode() == typexpr {
check.errorf(e.Sel, InvalidMethodExpr, "invalid method expression %s.%s (needs pointer receiver (*%s).%s)", x.typ(), sel, x.typ(), sel)
} else {
check.errorf(e.Sel, InvalidMethodExpr, "cannot call pointer method %s on %s", sel, x.typ())
if isInterfacePtr(x.typ()) {
why = check.interfacePtrError(x.typ())
} else {
- alt, _, _ := lookupFieldOrMethod(x.typ(), x.mode_ == variable, check.pkg, sel, true)
+ alt, _, _ := lookupFieldOrMethod(x.typ(), x.mode() == variable, check.pkg, sel, true)
why = check.lookupError(x.typ(), sel, alt, false)
}
check.errorf(e.Sel, MissingFieldOrMethod, "%s.%s undefined (%s)", x.expr, sel, why)
switch obj := obj.(type) {
case *Var:
- if x.mode_ == typexpr {
+ if x.mode() == typexpr {
check.errorf(e.X, MissingFieldOrMethod, "operand for field selector %s must be value of type %s", sel, x.typ())
goto Error
}
// field value
check.recordSelection(e, FieldVal, x.typ(), obj, index, indirect)
- if x.mode_ == variable || indirect {
+ if x.mode() == variable || indirect {
x.mode_ = variable
} else {
x.mode_ = value
check.objDecl(obj) // ensure fully set-up signature
check.addDeclDep(obj)
- if x.mode_ == typexpr {
+ if x.mode() == typexpr {
// method expression
check.recordSelection(e, MethodExpr, x.typ(), obj, index, indirect)
// any incomplete interfaces so they are available to NewMethodSet
// (which assumes that interfaces have been completed already).
typ := x.typ_
- if x.mode_ == variable {
+ if x.mode() == variable {
// If typ is not an (unnamed) pointer or an interface,
// use *typ instead, because the method set of *typ
// includes the methods of typ.
default:
check.rawExpr(nil, &x, e, nil, true)
}
- return x.mode_ != invalid
+ return x.mode() != invalid
}
// For untyped constants, it checks that the value doesn't become
// arbitrarily large.
func (check *Checker) overflow(x *operand, opPos token.Pos) {
- assert(x.mode_ == constant_)
+ assert(x.mode() == constant_)
if x.val.Kind() == constant.Unknown {
// TODO(gri) We should report exactly what went wrong. At the
//
// If no such representation is possible, it returns a non-zero error code.
func (check *Checker) representation(x *operand, typ *Basic) (constant.Value, Code) {
- assert(x.mode_ == constant_)
+ assert(x.mode() == constant_)
v := x.val
if !representableConst(x.val, check, typ, &v) {
if isNumeric(x.typ()) && isNumeric(typ) {
// conversion type-checks the conversion T(x).
// The result is in x.
func (check *Checker) conversion(x *operand, T Type) {
- constArg := x.mode_ == constant_
+ constArg := x.mode() == constant_
constConvertibleTo := func(T Type, val *constant.Value) bool {
switch t, _ := T.Underlying().(*Basic); {
// ok
} else if isNonTypeParamInterface(T) || constArg && !isConstType(T) || !isTypes2 && x.isNil() {
final = Default(x.typ()) // default type of untyped nil is untyped nil
- } else if x.mode_ == constant_ && isInteger(x.typ()) && allString(T) {
+ } else if x.mode() == constant_ && isInteger(x.typ()) && allString(T) {
final = x.typ()
}
check.updateExprType(x.expr, final, true)
// The unary expression e may be nil. It's passed in for better error messages only.
func (check *Checker) unary(x *operand, e *ast.UnaryExpr) {
check.expr(nil, x, e.X)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
case token.AND:
// spec: "As an exception to the addressability
// requirement x may also be a composite literal."
- if _, ok := ast.Unparen(e.X).(*ast.CompositeLit); !ok && x.mode_ != variable {
+ if _, ok := ast.Unparen(e.X).(*ast.CompositeLit); !ok && x.mode() != variable {
check.errorf(x, UnaddressableOperand, invalidOp+"cannot take address of %s", x)
x.mode_ = invalid
return
return
}
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
if x.val.Kind() == constant.Unknown {
// nothing to do (and don't cause an error below in the overflow check)
return
// If x is a constant, it must be representable as a value of typ.
c := operand{old.mode, x, old.typ, old.val, 0}
check.convertUntyped(&c, typ)
- if c.mode_ == invalid {
+ if c.mode() == invalid {
return
}
}
// If x is a constant operand, the returned constant.Value will be the
// representation of x in this context.
func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, constant.Value, Code) {
- if x.mode_ == invalid || isTyped(x.typ()) || !isValid(target) {
+ if x.mode() == invalid || isTyped(x.typ()) || !isValid(target) {
return x.typ(), nil, 0
}
// x is untyped
switch u := target.Underlying().(type) {
case *Basic:
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
v, code := check.representation(x, u)
if code != 0 {
return nil, nil, code
}
// comparison is ok
- if x.mode_ == constant_ && y.mode_ == constant_ {
+ if x.mode() == constant_ && y.mode() == constant_ {
x.val = constant.MakeBool(constant.Compare(x.val, op, y.val))
// The operands are never materialized; no need to update
// their types.
// TODO(gri) This function seems overly complex. Revisit.
var xval constant.Value
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
xval = constant.ToInt(x.val)
}
// Check that constants are representable by uint, but do not convert them
// (see also go.dev/issue/47243).
var yval constant.Value
- if y.mode_ == constant_ {
+ if y.mode() == constant_ {
// Provide a good error message for negative shift counts.
yval = constant.ToInt(y.val) // consider -1, 1.0, but not -1.1
if yval.Kind() == constant.Int && constant.Sign(yval) < 0 {
// Caution: Check for representability here, rather than in the switch
// below, because isInteger includes untyped integers (was bug go.dev/issue/43697).
check.representable(y, Typ[Uint])
- if y.mode_ == invalid {
+ if y.mode() == invalid {
x.mode_ = invalid
return
}
// This is incorrect, but preserves pre-existing behavior.
// See also go.dev/issue/47410.
check.convertUntyped(y, Typ[Uint])
- if y.mode_ == invalid {
+ if y.mode() == invalid {
x.mode_ = invalid
return
}
}
}
- if x.mode_ == constant_ {
- if y.mode_ == constant_ {
+ if x.mode() == constant_ {
+ if y.mode() == constant_ {
// if either x or y has an unknown value, the result is unknown
if x.val.Kind() == constant.Unknown || y.val.Kind() == constant.Unknown {
x.val = constant.MakeUnknown()
check.expr(nil, x, lhs)
check.expr(nil, &y, rhs)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
- if y.mode_ == invalid {
+ if y.mode() == invalid {
x.mode_ = invalid
x.expr = y.expr
return
}
check.matchTypes(x, &y)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
if op == token.QUO || op == token.REM {
// check for zero divisor
- if (x.mode_ == constant_ || allInteger(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.error(&y, DivByZero, invalidOp+"division by zero")
x.mode_ = invalid
return
}
// check for divisor underflow in complex division (see go.dev/issue/20227)
- if x.mode_ == constant_ && y.mode_ == constant_ && isComplex(x.typ()) {
+ if x.mode() == constant_ && y.mode() == constant_ && isComplex(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 {
}
}
- if x.mode_ == constant_ && y.mode_ == constant_ {
+ if x.mode() == constant_ && y.mode() == constant_ {
// if either x or y has an unknown value, the result is unknown
if x.val.Kind() == constant.Unknown || y.val.Kind() == constant.Unknown {
x.val = constant.MakeUnknown()
if mayConvert(x, y) {
check.convertUntyped(x, y.typ())
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
check.convertUntyped(y, x.typ())
- if y.mode_ == invalid {
+ if y.mode() == invalid {
x.mode_ = invalid
return
}
// from a non-nil target T, nonGeneric reports an error and invalidates x.mode and x.typ.
// Otherwise it leaves x alone.
func (check *Checker) nonGeneric(T *target, x *operand) {
- if x.mode_ == invalid || x.mode_ == novalue {
+ if x.mode() == invalid || x.mode() == novalue {
return
}
var what string
case *ast.BasicLit:
check.basicLit(x, e)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
goto Error
}
case *ast.FuncLit:
check.funcLit(x, e)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
goto Error
}
case *ast.CompositeLit:
check.compositeLit(x, e, hint)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
goto Error
}
}
check.funcInst(T, e.Pos(), x, ix, true)
}
- if x.mode_ == invalid {
+ if x.mode() == invalid {
goto Error
}
case *ast.SliceExpr:
check.sliceExpr(x, e)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
goto Error
}
case *ast.TypeAssertExpr:
check.expr(nil, x, e.X)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
goto Error
}
// x.(type) expressions are handled explicitly in type switches
case *ast.StarExpr:
check.exprOrType(x, e.X, false)
- switch x.mode_ {
+ switch x.mode() {
case invalid:
goto Error
case typexpr:
case *ast.UnaryExpr:
check.unary(x, e)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
goto Error
}
if e.Op == token.ARROW {
case *ast.BinaryExpr:
check.binary(x, e, e.X, e.Y, e.Op, e.OpPos)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
goto Error
}
check.rawExpr(nil, &x, e, nil, false)
check.exclude(&x, 1<<novalue|1<<builtin|1<<typexpr)
- if t, ok := x.typ().(*Tuple); ok && x.mode_ != invalid {
+ if t, ok := x.typ().(*Tuple); ok && x.mode() != invalid {
// multiple values
list = make([]*operand, t.Len())
for i, v := range t.vars {
// exactly one (possibly invalid or comma-ok) value
list = []*operand{&x}
- if allowCommaOk && (x.mode_ == mapindex || x.mode_ == commaok || x.mode_ == commaerr) {
+ if allowCommaOk && (x.mode() == mapindex || x.mode() == commaok || x.mode() == commaerr) {
x2 := &operand{mode_: value, expr: e, typ_: Typ[UntypedBool]}
- if x.mode_ == commaerr {
+ if x.mode() == commaerr {
x2.typ_ = universeError
}
list = append(list, x2)
// exclude reports an error if x.mode is in modeset and sets x.mode to invalid.
// The modeset may contain any of 1<<novalue, 1<<builtin, 1<<typexpr.
func (check *Checker) exclude(x *operand, modeset uint) {
- if modeset&(1<<x.mode_) != 0 {
+ if modeset&(1<<x.mode()) != 0 {
var msg string
var code Code
- switch x.mode_ {
+ switch x.mode() {
case novalue:
if modeset&(1<<typexpr) != 0 {
msg = "%s used as value"
// singleValue reports an error if x describes a tuple and sets x.mode to invalid.
func (check *Checker) singleValue(x *operand) {
- if x.mode_ == value {
+ if x.mode() == value {
// tuple types are never named - no need for underlying type below
if t, ok := x.typ().(*Tuple); ok {
assert(t.Len() != 1)
check.exprOrType(x, e.x, true)
// x may be generic
- switch x.mode_ {
+ switch x.mode() {
case invalid:
check.use(e.indices...)
return false
// x should not be generic at this point, but be safe and check
check.nonGeneric(nil, x)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return false
}
case *Basic:
if isString(typ) {
valid = true
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
length = int64(len(constant.StringVal(x.val)))
}
// an indexed string always yields a byte value
case *Array:
valid = true
length = typ.len
- if x.mode_ != variable {
+ if x.mode() != variable {
x.mode_ = value
}
x.typ_ = typ.elem
case *Array:
l = t.len
e = t.elem
- if x.mode_ != variable {
+ if x.mode() != variable {
mode = value
}
case *Pointer:
func (check *Checker) sliceExpr(x *operand, e *ast.SliceExpr) {
check.expr(nil, x, e.X)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
check.use(e.Low, e.High, e.Max)
return
}
return
}
valid = true
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
length = int64(len(constant.StringVal(x.val)))
}
// spec: "For untyped string operands the result
case *Array:
valid = true
length = u.len
- if x.mode_ != variable {
+ if x.mode() != variable {
check.errorf(x, NonSliceableOperand, "cannot slice unaddressable value %s", x)
x.mode_ = invalid
return
return
}
- if x.mode_ != constant_ {
+ if x.mode() != constant_ {
return x.typ(), -1
}
}
func (check *Checker) isValidIndex(x *operand, code Code, what string, allowNegative bool) bool {
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return false
}
// spec: "a constant index that is untyped is given type int"
check.convertUntyped(x, Typ[Int])
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return false
}
return false
}
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
// spec: "a constant index must be non-negative ..."
if !allowNegative && constant.Sign(x.val) < 0 {
check.errorf(x, code, invalidArg+"%s %s must not be negative", what, x)
// If we have invalid (ordinary) arguments, an error was reported before.
// Avoid additional inference errors and exit early (go.dev/issue/60434).
for _, arg := range args {
- if arg.mode_ == invalid {
+ if arg.mode() == invalid {
return nil
}
}
}
for i, arg := range args {
- if arg.mode_ == invalid {
+ if arg.mode() == invalid {
// An error was reported earlier. Ignore this arg
// and continue, we may still be able to infer all
// targs resulting in fewer follow-on errors.
}
}
x.setConst(e.Kind, e.Value)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
// The parser already establishes syntactic correctness.
// If we reach here it's because of number under-/overflow.
// TODO(gri) setConst (and in turn the go/constant package)
}
check.exprWithHint(x, kv.Key, utyp.key)
check.assignment(x, utyp.key, "map literal")
- if x.mode_ == invalid {
+ if x.mode() == invalid {
continue
}
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
duplicate := false
xkey := keyVal(x.val)
if keyIsInterface {
id builtinId
}
+func (x *operand) mode() operandMode {
+ return x.mode_
+}
+
func (x *operand) typ() Type {
return x.typ_
}
func (x *operand) isValid() bool {
- return x.mode_ != invalid
+ return x.mode() != invalid
}
// Pos returns the position of the expression corresponding to x.
func operandString(x *operand, qf Qualifier) string {
// special-case nil
if isTypes2 {
- if x.mode_ == nilvalue {
+ if x.mode() == nilvalue {
switch x.typ() {
case nil, Typ[Invalid]:
return "nil (with invalid type)"
}
}
} else { // go/types
- if x.mode_ == value && x.typ() == Typ[UntypedNil] {
+ if x.mode() == value && x.typ() == Typ[UntypedNil] {
return "nil"
}
}
if x.expr != nil {
expr = ExprString(x.expr)
} else {
- switch x.mode_ {
+ switch x.mode() {
case builtin:
expr = predeclaredFuncs[x.id].name
case typexpr:
// <untyped kind>
hasType := false
- switch x.mode_ {
+ switch x.mode() {
case invalid, novalue, builtin, typexpr:
// no type
default:
}
// <mode>
- buf.WriteString(operandModeString[x.mode_])
+ buf.WriteString(operandModeString[x.mode()])
// <val>
- if x.mode_ == constant_ {
+ if x.mode() == constant_ {
if s := x.val.String(); s != expr {
buf.WriteByte(' ')
buf.WriteString(s)
// isNil reports whether x is the (untyped) nil value.
func (x *operand) isNil() bool {
if isTypes2 {
- return x.mode_ == nilvalue
+ return x.mode() == nilvalue
} else { // go/types
- return x.mode_ == value && x.typ() == Typ[UntypedNil]
+ return x.mode() == value && x.typ() == Typ[UntypedNil]
}
}
// if assignableTo is invoked through an exported API call, i.e., when all
// methods have been type-checked.
func (x *operand) assignableTo(check *Checker, T Type, cause *string) (bool, Code) {
- if x.mode_ == invalid || !isValid(T) {
+ if x.mode() == invalid || !isValid(T) {
return true, 0 // avoid spurious errors
}
check.hasCallOrRecv = false
check.expr(nil, &x, rangeVar)
- if isTypes2 && x.mode_ != invalid && sValue == nil && !check.hasCallOrRecv {
+ if isTypes2 && x.mode() != invalid && sValue == nil && !check.hasCallOrRecv {
if t, ok := arrayPtrDeref(x.typ().Underlying()).(*Array); ok {
for {
// Put constant info on the thing inside parentheses.
// determine key/value types
var key, val Type
- if x.mode_ != invalid {
+ if x.mode() != invalid {
k, v, cause, ok := rangeKeyVal(check, x.typ(), func(v goVersion) bool {
return check.allowVersion(v)
})
// If the assignment succeeded, if x was untyped before, it now
// has a type inferred via the assignment. It must be an integer.
// (go.dev/issues/67027)
- if x.mode_ != invalid && !isInteger(x.typ()) {
+ if x.mode() != invalid && !isInteger(x.typ()) {
check.softErrorf(lhs, InvalidRangeExpr, "cannot use iteration variable of type %s", x.typ())
}
} else {
// TODO(gri) this code can be simplified
var typ Type
var val constant.Value
- switch x.mode_ {
+ switch x.mode() {
case invalid:
typ = Typ[Invalid]
case novalue:
if isUntyped(typ) {
// delay type and value recording until we know the type
// or until the end of type checking
- check.rememberUntyped(x.expr, false, x.mode_, typ.(*Basic), val)
+ check.rememberUntyped(x.expr, false, x.mode(), typ.(*Basic), val)
} else {
- check.recordTypeAndValue(x.expr, x.mode_, typ, val)
+ check.recordTypeAndValue(x.expr, x.mode(), typ, val)
}
}
func (check *Checker) recordCommaOkTypes(x ast.Expr, a []*operand) {
assert(x != nil)
assert(len(a) == 2)
- if a[0].mode_ == invalid {
+ if a[0].mode() == invalid {
return
}
t0, t1 := a[0].typ(), a[1].typ()
for _, e := range values {
var v operand
check.expr(nil, &v, e)
- if x.mode_ == invalid || v.mode_ == invalid {
+ if x.mode() == invalid || v.mode() == invalid {
continue L
}
check.convertUntyped(&v, x.typ())
- if v.mode_ == invalid {
+ if v.mode() == invalid {
continue L
}
// Order matters: By comparing v against x, error positions are at the case values.
res := v // keep original v unchanged
check.comparison(&res, x, token.EQL, true)
- if res.mode_ == invalid {
+ if res.mode() == invalid {
continue L
}
- if v.mode_ != constant_ {
+ if v.mode() != constant_ {
continue L // we're done
}
// look for duplicate values
kind := check.rawExpr(nil, &x, s.X, nil, false)
var msg string
var code Code
- switch x.mode_ {
+ switch x.mode() {
default:
if kind == statement {
return
var ch, val operand
check.expr(nil, &ch, s.Chan)
check.expr(nil, &val, s.Value)
- if ch.mode_ == invalid || val.mode_ == invalid {
+ if ch.mode() == invalid || val.mode() == invalid {
return
}
if elem := check.chanElem(inNode(s, s.Arrow), &ch, false); elem != nil {
var x operand
check.expr(nil, &x, s.X)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
if !allNumeric(x.typ()) {
Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"} // use x's position
check.binary(&x, nil, s.X, Y, op, s.TokPos)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
check.assignVar(s.X, nil, &x, "assignment")
}
var x operand
check.binary(&x, nil, s.Lhs[0], s.Rhs[0], op, s.TokPos)
- if x.mode_ == invalid {
+ if x.mode() == invalid {
return
}
check.assignVar(s.Lhs[0], nil, &x, "assignment")
check.simpleStmt(s.Init)
var x operand
check.expr(nil, &x, s.Cond)
- if x.mode_ != invalid && !allBoolean(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)
// By checking assignment of x to an invisible temporary
// (as a compiler would), we get all the relevant checks.
check.assignment(&x, nil, "switch expression")
- if x.mode_ != invalid && !Comparable(x.typ()) && !hasNil(x.typ()) {
+ if x.mode() != invalid && !Comparable(x.typ()) && !hasNil(x.typ()) {
check.errorf(&x, InvalidExprSwitch, "cannot switch on %s (%s is not comparable)", &x, x.typ())
x.mode_ = invalid
}
{
var x operand
check.expr(nil, &x, expr.X)
- if x.mode_ != invalid {
+ if x.mode() != invalid {
if isTypeParam(x.typ()) {
check.errorf(&x, InvalidTypeSwitch, "cannot use type switch on type parameter value %s", &x)
} else if IsInterface(x.typ()) {
if s.Cond != nil {
var x operand
check.expr(nil, &x, s.Cond)
- if x.mode_ != invalid && !allBoolean(x.typ()) {
+ if x.mode() != invalid && !allBoolean(x.typ()) {
check.error(s.Cond, InvalidCond, "non-boolean condition in for statement")
}
}
var x operand
check.ident(&x, e, true)
- switch x.mode_ {
+ switch x.mode() {
case typexpr:
return x.typ()
case invalid:
var x operand
check.selector(&x, e, true)
- switch x.mode_ {
+ switch x.mode() {
case typexpr:
return x.typ()
case invalid:
var x operand
check.expr(nil, &x, e)
- if x.mode_ != constant_ {
- if x.mode_ != invalid {
+ if x.mode() != constant_ {
+ if x.mode() != invalid {
check.errorf(&x, InvalidArrayLen, "array length %s must be constant", &x)
}
return -1