// The behavior of AssignableTo is unspecified if V or T is Typ[Invalid] or an
// uninstantiated generic type.
func AssignableTo(V, T Type) bool {
- x := operand{mode: value, typ_: V}
+ x := operand{mode_: value, typ_: V}
ok, _ := x.assignableTo(nil, T, nil) // check not needed for non-constant x
return ok
}
// The behavior of ConvertibleTo is unspecified if V or T is Typ[Invalid] or an
// uninstantiated generic type.
func ConvertibleTo(V, T Type) bool {
- x := operand{mode: value, typ_: V}
+ x := operand{mode_: value, typ_: V}
return x.convertibleTo(nil, T, nil) // check not needed for non-constant x
}
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:
// we may get here because of other problems (go.dev/issue/39634, crash 12)
// TODO(gri) do we need a new "generic" error code here?
check.errorf(x, IncompatibleAssign, "cannot assign %s to %s in %s", x, T, context)
- x.mode = invalid
+ x.mode_ = invalid
return
}
if x.isNil() {
if T == nil {
check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context)
- x.mode = invalid
+ x.mode_ = invalid
return
}
} else if T == nil || isNonTypeParamInterface(T) {
if T == nil || isNonTypeParamInterface(T) {
if T == nil && x.typ_ == Typ[UntypedNil] {
check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context)
- x.mode = invalid
+ x.mode_ = invalid
return
}
target = Default(x.typ_)
code = IncompatibleAssign
}
check.error(x, code, msg)
- x.mode = invalid
+ x.mode_ = invalid
return
}
if val != nil {
// A generic (non-instantiated) function value cannot be assigned to a variable.
if sig, _ := x.typ_.Underlying().(*Signature); sig != nil && sig.TypeParams().Len() > 0 {
check.errorf(x, WrongTypeArgCount, "cannot use generic function %s without instantiation in %s", x, context)
- x.mode = invalid
+ x.mode_ = invalid
return
}
} else {
check.errorf(x, code, "cannot use %s as %s value in %s", x, T, context)
}
- x.mode = invalid
+ x.mode_ = invalid
}
}
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]
}
- x.mode = invalid
+ x.mode_ = invalid
return
}
if typ == Typ[UntypedNil] {
check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context)
lhs.typ = Typ[Invalid]
- x.mode = invalid
+ x.mode_ = invalid
return
}
typ = Default(typ)
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]
}
T := check.lhsVar(lhs) // nil if lhs is _
if !isValid(T) {
if x != nil {
- x.mode = invalid
+ x.mode_ = invalid
} else {
check.use(rhs)
}
}
// 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
}
}
if check.recordTypes() {
check.recordBuiltinType(call.Fun, sig)
}
- x.mode = value
+ x.mode_ = value
// x.typ is unchanged
case _Cap, _Len:
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 {
check.recordBuiltinType(call.Fun, makeSig(Typ[Int], x.typ_))
}
- x.mode = mode
+ x.mode_ = mode
x.typ_ = Typ[Int]
x.val = val
return
}
- x.mode = novalue
+ x.mode_ = novalue
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(nil, x.typ_))
}
}) {
return
}
- x.mode = novalue
+ x.mode_ = novalue
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(nil, x.typ_))
}
// 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
+ 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_))
}
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(Typ[Int], x.typ_, y.typ_))
}
- x.mode = value
+ x.mode_ = value
x.typ_ = Typ[Int]
case _Delete:
*x = *args[1] // key
check.assignment(x, key, "argument to delete")
- if x.mode == invalid {
+ if x.mode_ == invalid {
return
}
- x.mode = novalue
+ x.mode_ = novalue
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(nil, map_, key))
}
// 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.val = constant.Imag(x.val)
}
} else {
- x.mode = value
+ x.mode_ = value
}
- if check.recordTypes() && x.mode != constant_ {
+ if check.recordTypes() && x.mode_ != constant_ {
check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ_))
}
check.error(argList[1], SwappedMakeArgs, invalidArg+"length and capacity swapped")
// safe to continue
}
- x.mode = value
+ x.mode_ = value
x.typ_ = T
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.typ_, types...))
}
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
}
} else {
- x.mode = value
+ x.mode_ = value
}
}
}
// If nargs == 1, make sure x.mode is either a value or a constant.
- if x.mode != constant_ {
- x.mode = value
+ 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_))
}
T := x.typ_
- x.mode = value
+ x.mode_ = value
x.typ_ = NewPointer(T)
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.typ_, T))
}
check.assignment(x, &emptyInterface, "argument to panic")
- if x.mode == invalid {
+ if x.mode_ == invalid {
return
}
- x.mode = novalue
+ x.mode_ = novalue
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(nil, &emptyInterface))
}
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_
}
}
- x.mode = novalue
+ x.mode_ = novalue
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(nil, params...))
}
case _Recover:
// recover() interface{}
- x.mode = value
+ x.mode_ = value
x.typ_ = &emptyInterface
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.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
}
return
}
- x.mode = value
+ x.mode_ = value
x.typ_ = Typ[UnsafePointer]
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.typ_, x.typ_, y.typ_))
case _Alignof:
// unsafe.Alignof(x T) uintptr
check.assignment(x, nil, "argument to unsafe.Alignof")
- if x.mode == invalid {
+ if x.mode_ == invalid {
return
}
if check.hasVarSize(x.typ_) {
- x.mode = value
+ x.mode_ = value
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], x.typ_))
}
} else {
- x.mode = constant_
+ x.mode_ = constant_
x.val = constant.MakeInt64(check.conf.alignof(x.typ_))
// result is constant - no need to record signature
}
}
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})
// simpler and also permits (or at least doesn't prevent) a compiler from re-
// arranging struct fields if it wanted to.
if check.hasVarSize(base) {
- x.mode = value
+ x.mode_ = value
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], obj.Type()))
}
check.errorf(x, TypeTooLarge, "%s is too large", x)
return
}
- x.mode = constant_
+ x.mode_ = constant_
x.val = constant.MakeInt64(offs)
// result is constant - no need to record signature
}
case _Sizeof:
// unsafe.Sizeof(x T) uintptr
check.assignment(x, nil, "argument to unsafe.Sizeof")
- if x.mode == invalid {
+ if x.mode_ == invalid {
return
}
if check.hasVarSize(x.typ_) {
- x.mode = value
+ x.mode_ = value
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], x.typ_))
}
check.errorf(x, TypeTooLarge, "%s is too large", x)
return
}
- x.mode = constant_
+ x.mode_ = constant_
x.val = constant.MakeInt64(size)
// result is constant - no need to record signature
}
return
}
- x.mode = value
+ x.mode_ = value
x.typ_ = NewSlice(ptr.base)
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.typ_, ptr, y.typ_))
return
}
- x.mode = value
+ x.mode_ = value
x.typ_ = NewPointer(slice.elem)
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.typ_, slice))
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
}
return
}
- x.mode = value
+ x.mode_ = value
x.typ_ = Typ[String]
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.typ_, NewPointer(universeByte), y.typ_))
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
}
- x.mode = value
+ x.mode_ = value
x.typ_ = NewPointer(universeByte)
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.typ_, Typ[String]))
// 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
}
// (no argument evaluated yet)
if nargs == 0 {
check.dump("%v: trace() without arguments", atPos(call))
- x.mode = novalue
+ x.mode_ = novalue
break
}
var t operand
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
}
xlist = syntax.UnpackListExpr(inst.Index)
targs = check.typeList(xlist)
if targs == nil {
- x.mode = invalid
+ x.mode_ = invalid
return nil
}
assert(len(targs) == len(xlist))
if got > want {
// Providing too many type arguments is always an error.
check.errorf(xlist[got-1], WrongTypeArgCount, "got %d type arguments but want %d", got, want)
- x.mode = invalid
+ x.mode_ = invalid
return nil
}
// or the result type in a return statement. Create a pseudo-expression for that operand
// that makes sense when reported in error messages from infer, below.
expr := syntax.NewName(x.Pos(), T.desc)
- args = []*operand{{mode: value, expr: expr, typ_: T.sig}}
+ args = []*operand{{mode_: value, expr: expr, typ_: T.sig}}
reverse = true
}
if !err.empty() {
err.report()
}
- x.mode = invalid
+ x.mode_ = invalid
return nil
}
got = len(targs)
sig = check.instantiateSignature(x.Pos(), x.expr, sig, targs, xlist)
x.typ_ = sig
- x.mode = value
+ x.mode_ = value
return nil
}
// 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_
- x.mode = invalid
+ x.mode_ = invalid
// We cannot convert a value to an incomplete type; make sure it's complete.
if !check.isComplete(T) {
x.expr = call
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)
// no need to check for non-genericity here
id := x.id
if !check.builtin(x, call, id) {
- x.mode = invalid
+ x.mode_ = invalid
}
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 err != nil {
check.errorf(x, InvalidCall, invalidOp+"cannot call %s: %s", x, err.format(check))
- x.mode = invalid
+ x.mode_ = invalid
x.expr = call
return statement
}
targs = check.typeList(xlist)
if targs == nil {
check.use(call.ArgList...)
- x.mode = invalid
+ x.mode_ = invalid
x.expr = call
return statement
}
if got > want {
check.errorf(xlist[want], WrongTypeArgCount, "got %d type arguments but want %d", got, want)
check.use(call.ArgList...)
- x.mode = invalid
+ x.mode_ = invalid
x.expr = call
return statement
}
// determine result
switch sig.results.Len() {
case 0:
- x.mode = novalue
+ x.mode_ = novalue
case 1:
if cgocall {
- x.mode = commaerr
+ x.mode_ = commaerr
} else {
- x.mode = value
+ x.mode_ = value
}
typ := sig.results.vars[0].typ // unpack tuple
// We cannot return a value of an incomplete type; make sure it's complete.
if !check.isComplete(typ) {
- x.mode = invalid
+ x.mode_ = invalid
x.expr = call
return statement
}
x.typ_ = typ
default:
- x.mode = value
+ x.mode_ = value
x.typ_ = sig.results
}
x.expr = call
// 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_) {
- x.mode = invalid
+ if x.mode_ == value && sig.TypeParams().Len() > 0 && isParameterized(sig.TypeParams().list(), x.typ_) {
+ x.mode_ = invalid
}
return statement
// 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 {
- resList[i] = &operand{mode: value, expr: e, typ_: v.typ}
+ resList[i] = &operand{mode_: value, expr: e, typ_: v.typ}
}
} else {
// x is exactly one value (possibly invalid or uninstantiated generic function).
switch exp := exp.(type) {
case *Const:
assert(exp.Val() != nil)
- x.mode = constant_
+ x.mode_ = constant_
x.typ_ = exp.typ
x.val = exp.val
case *TypeName:
- x.mode = typexpr
+ x.mode_ = typexpr
x.typ_ = exp.typ
case *Var:
- x.mode = variable
+ x.mode_ = variable
x.typ_ = exp.typ
if pkg.cgo && strings.HasPrefix(exp.name, "_Cvar_") {
x.typ_ = x.typ_.(*Pointer).base
}
case *Func:
- x.mode = funcMode
+ x.mode_ = funcMode
x.typ_ = exp.typ
if pkg.cgo && strings.HasPrefix(exp.name, "_Cmacro_") {
- x.mode = value
+ x.mode_ = value
x.typ_ = x.typ_.(*Signature).results.vars[0].typ
}
case *Builtin:
- x.mode = builtin
+ x.mode_ = builtin
x.typ_ = exp.typ
x.id = exp.id
default:
}
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 {
- x.mode = variable
+ if x.mode_ == variable || indirect {
+ x.mode_ = variable
} else {
- x.mode = value
+ x.mode_ = value
}
x.typ_ = obj.typ
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)
}
}
params = append([]*Var{NewParam(sig.recv.pos, sig.recv.pkg, name, x.typ_)}, params...)
- x.mode = value
+ x.mode_ = value
x.typ_ = &Signature{
tparams: sig.tparams,
params: NewTuple(params...),
// addressability, should we report the type &(x.typ) instead?
check.recordSelection(e, MethodVal, x.typ_, obj, index, indirect)
- x.mode = value
+ x.mode_ = value
// remove receiver
sig := *obj.typ.(*Signature)
return
Error:
- x.mode = invalid
+ x.mode_ = invalid
x.typ_ = Typ[Invalid]
x.expr = e
}
func (check *Checker) use1(e syntax.Expr, lhs bool) bool {
var x operand
- x.mode = value // anything but invalid
+ x.mode_ = value // anything but invalid
switch n := syntax.Unparen(e).(type) {
case nil:
// nothing to do
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
v, code := check.representation(x, typ)
if code != 0 {
check.invalidConversion(code, x, typ)
- x.mode = invalid
+ x.mode_ = invalid
return
}
assert(v != nil)
//
// 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) {
t = safeUnderlying(target)
}
check.invalidConversion(code, x, t)
- x.mode = invalid
+ x.mode_ = invalid
return
}
if val != nil {
// 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); {
// (go.dev/issue/63563)
if !ok && isInteger(x.typ_) && isInteger(T) {
check.errorf(x, InvalidConversion, "constant %s overflows %s", x.val, T)
- x.mode = invalid
+ x.mode_ = invalid
return
}
case constArg && isTypeParam(T):
}
return true
})
- x.mode = value // type parameters are not constants
+ x.mode_ = value // type parameters are not constants
case x.convertibleTo(check, T, &cause):
// non-constant conversion
ok = true
- x.mode = value
+ x.mode_ = value
}
if !ok {
} else {
check.errorf(x, InvalidConversion, "cannot convert %s to type %s", x, T)
}
- x.mode = invalid
+ x.mode_ = invalid
return
}
// 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
+ x.mode_ = invalid
return
}
- x.mode = value
+ x.mode_ = value
x.typ_ = &Pointer{base: x.typ_}
return
case syntax.Recv:
// We cannot receive a value with an incomplete type; make sure it's complete.
if elem := check.chanElem(x, x, true); elem != nil && check.isComplete(elem) {
- x.mode = commaok
+ x.mode_ = commaok
x.typ_ = elem
check.hasCallOrRecv = true
return
}
- x.mode = invalid
+ x.mode_ = invalid
return
case syntax.Tilde:
// Provide a better error position and message than what check.op below would do.
if !allInteger(x.typ_) {
check.error(e, UndefinedOp, "cannot use ~ outside of interface or type constraint")
- x.mode = invalid
+ x.mode_ = invalid
return
}
check.error(e, UndefinedOp, "cannot use ~ outside of interface or type constraint (use ^ for bitwise complement)")
}
if !check.op(unaryOpPredicates, x, op) {
- x.mode = invalid
+ x.mode_ = invalid
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
return
}
- x.mode = value
+ x.mode_ = value
// x.typ remains unchanged
}
// 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
func (check *Checker) comparison(x, y *operand, op syntax.Operator, switchCase bool) {
// Avoid spurious errors if any of the operands has an invalid type (go.dev/issue/54405).
if !isValid(x.typ_) || !isValid(y.typ_) {
- x.mode = invalid
+ x.mode_ = invalid
return
}
}
// 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.
} else {
- x.mode = value
+ x.mode_ = value
// The operands have now their final types, which at run-
// time will be materialized. Update the expression trees.
// If the current types are untyped, the materialized type
} else {
check.errorf(errOp, code, invalidOp+"%s %s %s (%s)", x.expr, op, y.expr, cause)
}
- x.mode = invalid
+ x.mode_ = invalid
}
// incomparableCause returns a more specific cause why typ is not comparable.
// 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)
}
} else {
// shift has no chance
check.errorf(x, InvalidShiftOperand, invalidOp+"shifted operand %s must be integer", x)
- x.mode = invalid
+ x.mode_ = invalid
return
}
// 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 {
check.errorf(y, InvalidShiftCount, invalidOp+"negative shift count %s", y)
- x.mode = invalid
+ x.mode_ = invalid
return
}
// 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 {
- x.mode = invalid
+ if y.mode_ == invalid {
+ x.mode_ = invalid
return
}
}
switch {
case allInteger(y.typ_):
if !allUnsigned(y.typ_) && !check.verifyVersionf(y, go1_13, invalidOp+"signed shift count %s", y) {
- x.mode = invalid
+ x.mode_ = invalid
return
}
case isUntyped(y.typ_):
// This is incorrect, but preserves pre-existing behavior.
// See also go.dev/issue/47410.
check.convertUntyped(y, Typ[Uint])
- if y.mode == invalid {
- x.mode = invalid
+ if y.mode_ == invalid {
+ x.mode_ = invalid
return
}
default:
check.errorf(y, InvalidShiftCount, invalidOp+"shift count %s must be integer", y)
- x.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()
s, ok := constant.Uint64Val(yval)
if !ok || s > shiftBound {
check.errorf(y, InvalidShiftCount, invalidOp+"invalid shift count %s", y)
- x.mode = invalid
+ x.mode_ = invalid
return
}
// The lhs is representable as an integer but may not be an integer
check.untyped[x.expr] = info
}
// keep x's type
- x.mode = value
+ x.mode_ = value
return
}
}
// non-constant shift - lhs must be an integer
if !allInteger(x.typ_) {
check.errorf(x, InvalidShiftOperand, invalidOp+"shifted operand %s must be integer", x)
- x.mode = invalid
+ x.mode_ = invalid
return
}
- x.mode = value
+ x.mode_ = value
}
var binaryOpPredicates opPredicates
check.expr(nil, x, lhs)
check.expr(nil, &y, rhs)
- if x.mode == invalid {
+ if x.mode_ == invalid {
return
}
- if y.mode == invalid {
- x.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
}
check.errorf(x, MismatchedTypes, invalidOp+"%s %s= %s (mismatched types %s and %s)", lhs, op, rhs, x.typ_, y.typ_)
}
}
- x.mode = invalid
+ x.mode_ = invalid
return
}
if !check.op(binaryOpPredicates, x, op) {
- x.mode = invalid
+ 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
+ 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 {
check.error(&y, DivByZero, invalidOp+"division by zero")
- x.mode = invalid
+ x.mode_ = invalid
return
}
}
}
- 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()
return
}
- x.mode = value
+ x.mode_ = value
// x.typ is unchanged
}
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 {
- x.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
}
if what != "" {
check.errorf(x.expr, WrongTypeArgCount, "cannot use generic %s %s without instantiation", what, x.expr)
- x.mode = invalid
+ x.mode_ = invalid
x.typ_ = Typ[Invalid]
}
}
func (check *Checker) exprInternal(T *target, x *operand, e syntax.Expr, hint Type) exprKind {
// make sure x has a valid state in case of bailout
// (was go.dev/issue/5770)
- x.mode = invalid
+ x.mode_ = invalid
x.typ_ = Typ[Invalid]
switch e := e.(type) {
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
goto Error
}
check.typeAssertion(e, x, T, false)
- x.mode = commaok
+ x.mode_ = commaok
x.typ_ = T
case *syntax.TypeSwitchGuard:
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:
if !check.isComplete(base) {
goto Error
}
- x.mode = variable
+ x.mode_ = variable
x.typ_ = base
}
break
}
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
}
case *syntax.ArrayType, *syntax.SliceType, *syntax.StructType, *syntax.FuncType,
*syntax.InterfaceType, *syntax.MapType, *syntax.ChanType:
- x.mode = typexpr
+ x.mode_ = typexpr
x.typ_ = check.typ(e)
// Note: rawExpr (caller of exprInternal) will call check.recordTypeAndValue
// even though check.typ has already called it. This is fine as both
return expression
Error:
- x.mode = invalid
+ x.mode_ = invalid
x.expr = e
return statement // avoid follow-up errors
}
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 {
- list[i] = &operand{mode: value, expr: e, typ_: v.typ}
+ list[i] = &operand{mode_: value, expr: e, typ_: v.typ}
}
return
}
// exactly one (possibly invalid or comma-ok) value
list = []*operand{&x}
- 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 allowCommaOk && (x.mode_ == mapindex || x.mode_ == commaok || x.mode_ == commaerr) {
+ x2 := &operand{mode_: value, expr: e, typ_: Typ[UntypedBool]}
+ 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"
panic("unreachable")
}
check.errorf(x, code, msg, x)
- x.mode = invalid
+ x.mode_ = invalid
}
}
// 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.errorf(x, TooManyValues, "multiple-value %s in single-value context", x)
- x.mode = invalid
+ x.mode_ = invalid
}
}
}
check.exprOrType(x, e.X, true)
// x may be generic
- switch x.mode {
+ switch x.mode_ {
case invalid:
check.use(e.Index)
return false
case typexpr:
// type instantiation
- x.mode = invalid
+ x.mode_ = invalid
// TODO(gri) here we re-evaluate e.X - try to avoid this
x.typ_ = check.varType(e)
if isValid(x.typ_) {
- x.mode = typexpr
+ x.mode_ = typexpr
}
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
}
// We cannot index on an incomplete type; make sure it's complete.
if !check.isComplete(x.typ_) {
- x.mode = invalid
+ x.mode_ = invalid
return false
}
switch typ := x.typ_.Underlying().(type) {
// Additionally, if x.typ is a pointer to an array type, indexing implicitly dereferences the value, meaning
// its base type must also be complete.
if !check.isComplete(typ.base) {
- x.mode = invalid
+ x.mode_ = invalid
return false
}
case *Map:
// Lastly, if x.typ is a map type, indexing must produce a value of a complete type, meaning
// its element type must also be complete.
if !check.isComplete(typ.elem) {
- x.mode = invalid
+ 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
// (not a constant) even if the string and the
// index are constant
- x.mode = value
+ x.mode_ = value
x.typ_ = universeByte // use 'byte' name
}
case *Array:
valid = true
length = typ.len
- if x.mode != variable {
- x.mode = value
+ if x.mode_ != variable {
+ x.mode_ = value
}
x.typ_ = typ.elem
if typ, _ := typ.base.Underlying().(*Array); typ != nil {
valid = true
length = typ.len
- x.mode = variable
+ x.mode_ = variable
x.typ_ = typ.elem
}
case *Slice:
valid = true
- x.mode = variable
+ x.mode_ = variable
x.typ_ = typ.elem
case *Map:
index := check.singleIndex(e)
if index == nil {
- x.mode = invalid
+ x.mode_ = invalid
return false
}
var key operand
check.expr(nil, &key, index)
check.assignment(&key, typ.key, "map index")
// ok to continue even if indexing failed - map element type is known
- x.mode = mapindex
+ x.mode_ = mapindex
x.typ_ = typ.elem
x.expr = e
return false
case *Array:
l = t.len
e = t.elem
- if x.mode != variable {
+ if x.mode_ != variable {
mode = value
}
case *Pointer:
if key != nil {
index := check.singleIndex(e)
if index == nil {
- x.mode = invalid
+ x.mode_ = invalid
return false
}
var k operand
check.expr(nil, &k, index)
check.assignment(&k, key, "map index")
// ok to continue even if indexing failed - map element type is known
- x.mode = mapindex
+ x.mode_ = mapindex
x.typ_ = elem
x.expr = e
return false
// no maps
valid = true
- x.mode = mode
+ x.mode_ = mode
x.typ_ = elem
}
}
if !valid {
check.errorf(e.Pos(), NonSliceableOperand, "cannot index %s", x)
check.use(e.Index)
- x.mode = invalid
+ x.mode_ = invalid
return false
}
index := check.singleIndex(e)
if index == nil {
- x.mode = invalid
+ x.mode_ = invalid
return false
}
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
}
// However, if x.typ is a pointer to an array type, slicing implicitly dereferences the value, meaning
// its base type must also be complete.
if p, ok := x.typ_.Underlying().(*Pointer); ok && !check.isComplete(p.base) {
- x.mode = invalid
+ x.mode_ = invalid
return
}
switch u := cu.(type) {
case nil:
// error reported above
- x.mode = invalid
+ x.mode_ = invalid
return
case *Basic:
at = e // e.Index[2] should be present but be careful
}
check.error(at, InvalidSliceExpr, invalidOp+"3-index slice of string")
- x.mode = invalid
+ x.mode_ = invalid
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
+ x.mode_ = invalid
return
}
x.typ_ = &Slice{elem: u.elem}
if !valid {
check.errorf(x, NonSliceableOperand, "cannot slice %s", x)
- x.mode = invalid
+ x.mode_ = invalid
return
}
- x.mode = value
+ x.mode_ = value
// spec: "Only the first index may be omitted; it defaults to 0."
if e.Full && (e.Index[1] == nil || e.Index[2] == nil) {
check.error(e, InvalidSyntaxTree, "2nd and 3rd index required in 3-index slice")
- x.mode = invalid
+ 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.
const limit = 10000
if len(e.Value) > limit {
check.errorf(e, InvalidConstVal, "excessively long constant: %s... (%d chars)", e.Value[:10], len(e.Value))
- x.mode = invalid
+ x.mode_ = invalid
return
}
}
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)
// should return an error describing the issue.
check.errorf(e, InvalidConstVal, "malformed constant: %s", e.Value)
- x.mode = invalid
+ x.mode_ = invalid
return
}
// Ensure that integer values don't overflow (go.dev/issue/54280).
check.funcBody(decl, "<function literal>", sig, e.Body, iota)
}).describef(e, "func literal")
}
- x.mode = value
+ x.mode_ = value
x.typ_ = sig
} else {
check.errorf(e, InvalidSyntaxTree, "invalid function literal %v", e)
- x.mode = invalid
+ x.mode_ = invalid
}
}
// We cannot create a literal of an incomplete type; make sure it's complete.
if !check.isComplete(base) {
- x.mode = invalid
+ x.mode_ = invalid
return
}
}
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 {
cause = " (no common underlying type)"
}
check.errorf(e, InvalidLit, "invalid composite literal%s type %s%s", qualifier, typ, cause)
- x.mode = invalid
+ x.mode_ = invalid
return
}
}
- x.mode = value
+ x.mode_ = value
x.typ_ = typ
}
// for built-in functions.
// The zero value of operand is a ready to use invalid operand.
type operand struct {
- mode operandMode
- expr syntax.Expr
- typ_ Type
- val constant.Value
- id builtinId
+ mode_ operandMode
+ expr syntax.Expr
+ typ_ Type
+ val constant.Value
+ id builtinId
}
// 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)
val := makeFromLiteral(lit, k)
if val.Kind() == constant.Unknown {
- x.mode = invalid
+ x.mode_ = invalid
x.typ_ = Typ[Invalid]
return
}
- x.mode = constant_
+ x.mode_ = constant_
x.typ_ = Typ[kind]
x.val = val
}
// 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.
// (and thus side-effects will not be computed
// by the backend).
check.record(&operand{
- mode: constant_,
- expr: rangeVar,
- typ_: Typ[Int],
- val: constant.MakeInt64(t.len),
- id: x.id,
+ mode_: constant_,
+ expr: rangeVar,
+ typ_: Typ[Int],
+ val: constant.MakeInt64(t.len),
+ id: x.id,
})
}
}
// 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)
})
check.initVar(obj, &x, "range clause")
} else {
var y operand
- y.mode = value
+ y.mode_ = value
y.expr = lhs // we don't have a better rhs expression to use here
y.typ_ = typ
check.initVar(obj, &y, "assignment") // error is on variable, use "assignment" not "range clause"
// 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 {
var y operand
- y.mode = value
+ y.mode_ = value
y.expr = lhs // we don't have a better rhs expression to use here
y.typ_ = typ
check.assignVar(lhs, nil, &y, "assignment") // error is on variable, use "assignment" not "range clause"
// 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
+ x.mode_ = invalid
}
} else {
// spec: "A missing switch expression is
// equivalent to the boolean value true."
- x.mode = constant_
+ x.mode_ = constant_
x.typ_ = Typ[Bool]
x.val = constant.MakeBool(true)
// TODO(gri) should have a better position here
{
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_) {
// If an error occurred, x.mode is set to invalid.
// If wantType is set, the identifier e is expected to denote a type.
func (check *Checker) ident(x *operand, e *syntax.Name, wantType bool) {
- x.mode = invalid
+ x.mode_ = invalid
x.expr = e
scope, obj := check.lookupScope(e.Value)
x.val = obj.val
}
assert(x.val != nil)
- x.mode = constant_
+ x.mode_ = constant_
case *TypeName:
- x.mode = typexpr
+ x.mode_ = typexpr
case *Var:
// It's ok to mark non-local variables, but ignore variables
if !isValid(typ) {
return
}
- x.mode = variable
+ x.mode_ = variable
case *Func:
check.addDeclDep(obj)
- x.mode = value
+ x.mode_ = value
case *Builtin:
x.id = obj.id
- x.mode = builtin
+ x.mode_ = builtin
case *Nil:
- x.mode = nilvalue
+ x.mode_ = nilvalue
default:
panic("unreachable")
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
// The behavior of AssignableTo is unspecified if V or T is Typ[Invalid] or an
// uninstantiated generic type.
func AssignableTo(V, T Type) bool {
- x := operand{mode: value, typ_: V}
+ x := operand{mode_: value, typ_: V}
ok, _ := x.assignableTo(nil, T, nil) // check not needed for non-constant x
return ok
}
// The behavior of ConvertibleTo is unspecified if V or T is Typ[Invalid] or an
// uninstantiated generic type.
func ConvertibleTo(V, T Type) bool {
- x := operand{mode: value, typ_: V}
+ x := operand{mode_: value, typ_: V}
return x.convertibleTo(nil, T, nil) // check not needed for non-constant x
}
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:
// we may get here because of other problems (go.dev/issue/39634, crash 12)
// TODO(gri) do we need a new "generic" error code here?
check.errorf(x, IncompatibleAssign, "cannot assign %s to %s in %s", x, T, context)
- x.mode = invalid
+ x.mode_ = invalid
return
}
if x.isNil() {
if T == nil {
check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context)
- x.mode = invalid
+ x.mode_ = invalid
return
}
} else if T == nil || isNonTypeParamInterface(T) {
if T == nil || isNonTypeParamInterface(T) {
if T == nil && x.typ_ == Typ[UntypedNil] {
check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context)
- x.mode = invalid
+ x.mode_ = invalid
return
}
target = Default(x.typ_)
code = IncompatibleAssign
}
check.error(x, code, msg)
- x.mode = invalid
+ x.mode_ = invalid
return
}
if val != nil {
// A generic (non-instantiated) function value cannot be assigned to a variable.
if sig, _ := x.typ_.Underlying().(*Signature); sig != nil && sig.TypeParams().Len() > 0 {
check.errorf(x, WrongTypeArgCount, "cannot use generic function %s without instantiation in %s", x, context)
- x.mode = invalid
+ x.mode_ = invalid
return
}
} else {
check.errorf(x, code, "cannot use %s as %s value in %s", x, T, context)
}
- x.mode = invalid
+ x.mode_ = invalid
}
}
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]
}
- x.mode = invalid
+ x.mode_ = invalid
return
}
if typ == Typ[UntypedNil] {
check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context)
lhs.typ = Typ[Invalid]
- x.mode = invalid
+ x.mode_ = invalid
return
}
typ = Default(typ)
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]
}
T := check.lhsVar(lhs) // nil if lhs is _
if !isValid(T) {
if x != nil {
- x.mode = invalid
+ x.mode_ = invalid
} else {
check.use(rhs)
}
}
// 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
}
}
if check.recordTypes() {
check.recordBuiltinType(call.Fun, sig)
}
- x.mode = value
+ x.mode_ = value
// x.typ is unchanged
case _Cap, _Len:
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 {
check.recordBuiltinType(call.Fun, makeSig(Typ[Int], x.typ_))
}
- x.mode = mode
+ x.mode_ = mode
x.typ_ = Typ[Int]
x.val = val
return
}
- x.mode = novalue
+ x.mode_ = novalue
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(nil, x.typ_))
}
}) {
return
}
- x.mode = novalue
+ x.mode_ = novalue
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(nil, x.typ_))
}
// 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
+ 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_))
}
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(Typ[Int], x.typ_, y.typ_))
}
- x.mode = value
+ x.mode_ = value
x.typ_ = Typ[Int]
case _Delete:
*x = *args[1] // key
check.assignment(x, key, "argument to delete")
- if x.mode == invalid {
+ if x.mode_ == invalid {
return
}
- x.mode = novalue
+ x.mode_ = novalue
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(nil, map_, key))
}
// 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.val = constant.Imag(x.val)
}
} else {
- x.mode = value
+ x.mode_ = value
}
- if check.recordTypes() && x.mode != constant_ {
+ if check.recordTypes() && x.mode_ != constant_ {
check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ_))
}
check.error(argList[1], SwappedMakeArgs, invalidArg+"length and capacity swapped")
// safe to continue
}
- x.mode = value
+ x.mode_ = value
x.typ_ = T
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.typ_, types...))
}
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
}
} else {
- x.mode = value
+ x.mode_ = value
}
}
}
// If nargs == 1, make sure x.mode is either a value or a constant.
- if x.mode != constant_ {
- x.mode = value
+ 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_))
}
T := x.typ_
- x.mode = value
+ x.mode_ = value
x.typ_ = NewPointer(T)
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.typ_, T))
}
check.assignment(x, &emptyInterface, "argument to panic")
- if x.mode == invalid {
+ if x.mode_ == invalid {
return
}
- x.mode = novalue
+ x.mode_ = novalue
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(nil, &emptyInterface))
}
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_
}
}
- x.mode = novalue
+ x.mode_ = novalue
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(nil, params...))
}
case _Recover:
// recover() interface{}
- x.mode = value
+ x.mode_ = value
x.typ_ = &emptyInterface
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.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
}
return
}
- x.mode = value
+ x.mode_ = value
x.typ_ = Typ[UnsafePointer]
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.typ_, x.typ_, y.typ_))
case _Alignof:
// unsafe.Alignof(x T) uintptr
check.assignment(x, nil, "argument to unsafe.Alignof")
- if x.mode == invalid {
+ if x.mode_ == invalid {
return
}
if check.hasVarSize(x.typ_) {
- x.mode = value
+ x.mode_ = value
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], x.typ_))
}
} else {
- x.mode = constant_
+ x.mode_ = constant_
x.val = constant.MakeInt64(check.conf.alignof(x.typ_))
// result is constant - no need to record signature
}
}
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})
// simpler and also permits (or at least doesn't prevent) a compiler from re-
// arranging struct fields if it wanted to.
if check.hasVarSize(base) {
- x.mode = value
+ x.mode_ = value
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], obj.Type()))
}
check.errorf(x, TypeTooLarge, "%s is too large", x)
return
}
- x.mode = constant_
+ x.mode_ = constant_
x.val = constant.MakeInt64(offs)
// result is constant - no need to record signature
}
case _Sizeof:
// unsafe.Sizeof(x T) uintptr
check.assignment(x, nil, "argument to unsafe.Sizeof")
- if x.mode == invalid {
+ if x.mode_ == invalid {
return
}
if check.hasVarSize(x.typ_) {
- x.mode = value
+ x.mode_ = value
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], x.typ_))
}
check.errorf(x, TypeTooLarge, "%s is too large", x)
return
}
- x.mode = constant_
+ x.mode_ = constant_
x.val = constant.MakeInt64(size)
// result is constant - no need to record signature
}
return
}
- x.mode = value
+ x.mode_ = value
x.typ_ = NewSlice(ptr.base)
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.typ_, ptr, y.typ_))
return
}
- x.mode = value
+ x.mode_ = value
x.typ_ = NewPointer(slice.elem)
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.typ_, slice))
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
}
return
}
- x.mode = value
+ x.mode_ = value
x.typ_ = Typ[String]
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.typ_, NewPointer(universeByte), y.typ_))
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
}
- x.mode = value
+ x.mode_ = value
x.typ_ = NewPointer(universeByte)
if check.recordTypes() {
check.recordBuiltinType(call.Fun, makeSig(x.typ_, Typ[String]))
// 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
}
// (no argument evaluated yet)
if nargs == 0 {
check.dump("%v: trace() without arguments", call.Pos())
- x.mode = novalue
+ x.mode_ = novalue
break
}
var t operand
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
}
xlist = ix.indices
targs = check.typeList(xlist)
if targs == nil {
- x.mode = invalid
+ x.mode_ = invalid
return nil
}
assert(len(targs) == len(xlist))
if got > want {
// Providing too many type arguments is always an error.
check.errorf(ix.indices[got-1], WrongTypeArgCount, "got %d type arguments but want %d", got, want)
- x.mode = invalid
+ x.mode_ = invalid
return nil
}
// that makes sense when reported in error messages from infer, below.
expr := ast.NewIdent(T.desc)
expr.NamePos = x.Pos() // correct position
- args = []*operand{{mode: value, expr: expr, typ_: T.sig}}
+ args = []*operand{{mode_: value, expr: expr, typ_: T.sig}}
reverse = true
}
if !err.empty() {
err.report()
}
- x.mode = invalid
+ x.mode_ = invalid
return nil
}
got = len(targs)
// instantiate function signature
sig = check.instantiateSignature(x.Pos(), x.expr, sig, targs, xlist)
x.typ_ = sig
- x.mode = value
+ x.mode_ = value
return nil
}
// 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_
- x.mode = invalid
+ x.mode_ = invalid
// We cannot convert a value to an incomplete type; make sure it's complete.
if !check.isComplete(T) {
x.expr = call
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
// no need to check for non-genericity here
id := x.id
if !check.builtin(x, call, id) {
- x.mode = invalid
+ x.mode_ = invalid
}
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 err != nil {
check.errorf(x, InvalidCall, invalidOp+"cannot call %s: %s", x, err.format(check))
- x.mode = invalid
+ x.mode_ = invalid
x.expr = call
return statement
}
targs = check.typeList(xlist)
if targs == nil {
check.use(call.Args...)
- x.mode = invalid
+ x.mode_ = invalid
x.expr = call
return statement
}
if got > want {
check.errorf(xlist[want], WrongTypeArgCount, "got %d type arguments but want %d", got, want)
check.use(call.Args...)
- x.mode = invalid
+ x.mode_ = invalid
x.expr = call
return statement
}
// determine result
switch sig.results.Len() {
case 0:
- x.mode = novalue
+ x.mode_ = novalue
case 1:
if cgocall {
- x.mode = commaerr
+ x.mode_ = commaerr
} else {
- x.mode = value
+ x.mode_ = value
}
typ := sig.results.vars[0].typ // unpack tuple
// We cannot return a value of an incomplete type; make sure it's complete.
if !check.isComplete(typ) {
- x.mode = invalid
+ x.mode_ = invalid
x.expr = call
return statement
}
x.typ_ = typ
default:
- x.mode = value
+ x.mode_ = value
x.typ_ = sig.results
}
x.expr = call
// 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_) {
- x.mode = invalid
+ if x.mode_ == value && sig.TypeParams().Len() > 0 && isParameterized(sig.TypeParams().list(), x.typ_) {
+ x.mode_ = invalid
}
return statement
// 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 {
- resList[i] = &operand{mode: value, expr: e, typ_: v.typ}
+ resList[i] = &operand{mode_: value, expr: e, typ_: v.typ}
}
} else {
// x is exactly one value (possibly invalid or uninstantiated generic function).
switch exp := exp.(type) {
case *Const:
assert(exp.Val() != nil)
- x.mode = constant_
+ x.mode_ = constant_
x.typ_ = exp.typ
x.val = exp.val
case *TypeName:
- x.mode = typexpr
+ x.mode_ = typexpr
x.typ_ = exp.typ
case *Var:
- x.mode = variable
+ x.mode_ = variable
x.typ_ = exp.typ
if pkg.cgo && strings.HasPrefix(exp.name, "_Cvar_") {
x.typ_ = x.typ_.(*Pointer).base
}
case *Func:
- x.mode = funcMode
+ x.mode_ = funcMode
x.typ_ = exp.typ
if pkg.cgo && strings.HasPrefix(exp.name, "_Cmacro_") {
- x.mode = value
+ x.mode_ = value
x.typ_ = x.typ_.(*Signature).results.vars[0].typ
}
case *Builtin:
- x.mode = builtin
+ x.mode_ = builtin
x.typ_ = exp.typ
x.id = exp.id
default:
}
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 {
- x.mode = variable
+ if x.mode_ == variable || indirect {
+ x.mode_ = variable
} else {
- x.mode = value
+ x.mode_ = value
}
x.typ_ = obj.typ
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)
}
}
params = append([]*Var{NewParam(sig.recv.pos, sig.recv.pkg, name, x.typ_)}, params...)
- x.mode = value
+ x.mode_ = value
x.typ_ = &Signature{
tparams: sig.tparams,
params: NewTuple(params...),
// 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.
}
}
- x.mode = value
+ x.mode_ = value
// remove receiver
sig := *obj.typ.(*Signature)
return
Error:
- x.mode = invalid
+ x.mode_ = invalid
x.typ_ = Typ[Invalid]
x.expr = e
}
func (check *Checker) use1(e ast.Expr, lhs bool) bool {
var x operand
- x.mode = value // anything but invalid
+ x.mode_ = value // anything but invalid
switch n := ast.Unparen(e).(type) {
case nil:
// nothing to do
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
v, code := check.representation(x, typ)
if code != 0 {
check.invalidConversion(code, x, typ)
- x.mode = invalid
+ x.mode_ = invalid
return
}
assert(v != nil)
//
// 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) {
t = safeUnderlying(target)
}
check.invalidConversion(code, x, t)
- x.mode = invalid
+ x.mode_ = invalid
return
}
if val != nil {
// 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); {
// (go.dev/issue/63563)
if !ok && isInteger(x.typ_) && isInteger(T) {
check.errorf(x, InvalidConversion, "constant %s overflows %s", x.val, T)
- x.mode = invalid
+ x.mode_ = invalid
return
}
case constArg && isTypeParam(T):
}
return true
})
- x.mode = value // type parameters are not constants
+ x.mode_ = value // type parameters are not constants
case x.convertibleTo(check, T, &cause):
// non-constant conversion
ok = true
- x.mode = value
+ x.mode_ = value
}
if !ok {
} else {
check.errorf(x, InvalidConversion, "cannot convert %s to type %s", x, T)
}
- x.mode = invalid
+ x.mode_ = invalid
return
}
// 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
+ x.mode_ = invalid
return
}
- x.mode = value
+ x.mode_ = value
x.typ_ = &Pointer{base: x.typ_}
return
case token.ARROW:
// We cannot receive a value with an incomplete type; make sure it's complete.
if elem := check.chanElem(x, x, true); elem != nil && check.isComplete(elem) {
- x.mode = commaok
+ x.mode_ = commaok
x.typ_ = elem
check.hasCallOrRecv = true
return
}
- x.mode = invalid
+ x.mode_ = invalid
return
case token.TILDE:
// Provide a better error position and message than what check.op below would do.
if !allInteger(x.typ_) {
check.error(e, UndefinedOp, "cannot use ~ outside of interface or type constraint")
- x.mode = invalid
+ x.mode_ = invalid
return
}
check.error(e, UndefinedOp, "cannot use ~ outside of interface or type constraint (use ^ for bitwise complement)")
}
if !check.op(unaryOpPredicates, x, op) {
- x.mode = invalid
+ x.mode_ = invalid
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
return
}
- x.mode = value
+ x.mode_ = value
// x.typ remains unchanged
}
// 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
func (check *Checker) comparison(x, y *operand, op token.Token, switchCase bool) {
// Avoid spurious errors if any of the operands has an invalid type (go.dev/issue/54405).
if !isValid(x.typ_) || !isValid(y.typ_) {
- x.mode = invalid
+ x.mode_ = invalid
return
}
}
// 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.
} else {
- x.mode = value
+ x.mode_ = value
// The operands have now their final types, which at run-
// time will be materialized. Update the expression trees.
// If the current types are untyped, the materialized type
} else {
check.errorf(errOp, code, invalidOp+"%s %s %s (%s)", x.expr, op, y.expr, cause)
}
- x.mode = invalid
+ x.mode_ = invalid
}
// incomparableCause returns a more specific cause why typ is not comparable.
// 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)
}
} else {
// shift has no chance
check.errorf(x, InvalidShiftOperand, invalidOp+"shifted operand %s must be integer", x)
- x.mode = invalid
+ x.mode_ = invalid
return
}
// 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 {
check.errorf(y, InvalidShiftCount, invalidOp+"negative shift count %s", y)
- x.mode = invalid
+ x.mode_ = invalid
return
}
// 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 {
- x.mode = invalid
+ if y.mode_ == invalid {
+ x.mode_ = invalid
return
}
}
switch {
case allInteger(y.typ_):
if !allUnsigned(y.typ_) && !check.verifyVersionf(y, go1_13, invalidOp+"signed shift count %s", y) {
- x.mode = invalid
+ x.mode_ = invalid
return
}
case isUntyped(y.typ_):
// This is incorrect, but preserves pre-existing behavior.
// See also go.dev/issue/47410.
check.convertUntyped(y, Typ[Uint])
- if y.mode == invalid {
- x.mode = invalid
+ if y.mode_ == invalid {
+ x.mode_ = invalid
return
}
default:
check.errorf(y, InvalidShiftCount, invalidOp+"shift count %s must be integer", y)
- x.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()
s, ok := constant.Uint64Val(yval)
if !ok || s > shiftBound {
check.errorf(y, InvalidShiftCount, invalidOp+"invalid shift count %s", y)
- x.mode = invalid
+ x.mode_ = invalid
return
}
// The lhs is representable as an integer but may not be an integer
check.untyped[x.expr] = info
}
// keep x's type
- x.mode = value
+ x.mode_ = value
return
}
}
// non-constant shift - lhs must be an integer
if !allInteger(x.typ_) {
check.errorf(x, InvalidShiftOperand, invalidOp+"shifted operand %s must be integer", x)
- x.mode = invalid
+ x.mode_ = invalid
return
}
- x.mode = value
+ x.mode_ = value
}
var binaryOpPredicates opPredicates
check.expr(nil, x, lhs)
check.expr(nil, &y, rhs)
- if x.mode == invalid {
+ if x.mode_ == invalid {
return
}
- if y.mode == invalid {
- x.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
}
check.errorf(posn, MismatchedTypes, invalidOp+"%s %s= %s (mismatched types %s and %s)", lhs, op, rhs, x.typ_, y.typ_)
}
}
- x.mode = invalid
+ x.mode_ = invalid
return
}
if !check.op(binaryOpPredicates, x, op) {
- x.mode = invalid
+ 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
+ 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 {
check.error(&y, DivByZero, invalidOp+"division by zero")
- x.mode = invalid
+ x.mode_ = invalid
return
}
}
}
- 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()
return
}
- x.mode = value
+ x.mode_ = value
// x.typ is unchanged
}
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 {
- x.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
}
if what != "" {
check.errorf(x.expr, WrongTypeArgCount, "cannot use generic %s %s without instantiation", what, x.expr)
- x.mode = invalid
+ x.mode_ = invalid
x.typ_ = Typ[Invalid]
}
}
func (check *Checker) exprInternal(T *target, x *operand, e ast.Expr, hint Type) exprKind {
// make sure x has a valid state in case of bailout
// (was go.dev/issue/5770)
- x.mode = invalid
+ x.mode_ = invalid
x.typ_ = Typ[Invalid]
switch e := e.(type) {
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
goto Error
}
check.typeAssertion(e, x, T, false)
- x.mode = commaok
+ x.mode_ = commaok
x.typ_ = T
case *ast.CallExpr:
case *ast.StarExpr:
check.exprOrType(x, e.X, false)
- switch x.mode {
+ switch x.mode_ {
case invalid:
goto Error
case typexpr:
if !check.isComplete(base) {
goto Error
}
- x.mode = variable
+ x.mode_ = variable
x.typ_ = base
}
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
}
case *ast.ArrayType, *ast.StructType, *ast.FuncType,
*ast.InterfaceType, *ast.MapType, *ast.ChanType:
- x.mode = typexpr
+ x.mode_ = typexpr
x.typ_ = check.typ(e)
// Note: rawExpr (caller of exprInternal) will call check.recordTypeAndValue
// even though check.typ has already called it. This is fine as both
return expression
Error:
- x.mode = invalid
+ x.mode_ = invalid
x.expr = e
return statement // avoid follow-up errors
}
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 {
- list[i] = &operand{mode: value, expr: e, typ_: v.typ}
+ list[i] = &operand{mode_: value, expr: e, typ_: v.typ}
}
return
}
// exactly one (possibly invalid or comma-ok) value
list = []*operand{&x}
- 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 allowCommaOk && (x.mode_ == mapindex || x.mode_ == commaok || x.mode_ == commaerr) {
+ x2 := &operand{mode_: value, expr: e, typ_: Typ[UntypedBool]}
+ 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"
panic("unreachable")
}
check.errorf(x, code, msg, x)
- x.mode = invalid
+ x.mode_ = invalid
}
}
// 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.errorf(x, TooManyValues, "multiple-value %s in single-value context", x)
- x.mode = invalid
+ x.mode_ = invalid
}
}
}
check.exprOrType(x, e.x, true)
// x may be generic
- switch x.mode {
+ switch x.mode_ {
case invalid:
check.use(e.indices...)
return false
case typexpr:
// type instantiation
- x.mode = invalid
+ x.mode_ = invalid
// TODO(gri) here we re-evaluate e.X - try to avoid this
x.typ_ = check.varType(e.orig)
if isValid(x.typ_) {
- x.mode = typexpr
+ x.mode_ = typexpr
}
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
}
// We cannot index on an incomplete type; make sure it's complete.
if !check.isComplete(x.typ_) {
- x.mode = invalid
+ x.mode_ = invalid
return false
}
switch typ := x.typ_.Underlying().(type) {
// Additionally, if x.typ is a pointer to an array type, indexing implicitly dereferences the value, meaning
// its base type must also be complete.
if !check.isComplete(typ.base) {
- x.mode = invalid
+ x.mode_ = invalid
return false
}
case *Map:
// Lastly, if x.typ is a map type, indexing must produce a value of a complete type, meaning
// its element type must also be complete.
if !check.isComplete(typ.elem) {
- x.mode = invalid
+ 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
// (not a constant) even if the string and the
// index are constant
- x.mode = value
+ x.mode_ = value
x.typ_ = universeByte // use 'byte' name
}
case *Array:
valid = true
length = typ.len
- if x.mode != variable {
- x.mode = value
+ if x.mode_ != variable {
+ x.mode_ = value
}
x.typ_ = typ.elem
if typ, _ := typ.base.Underlying().(*Array); typ != nil {
valid = true
length = typ.len
- x.mode = variable
+ x.mode_ = variable
x.typ_ = typ.elem
}
case *Slice:
valid = true
- x.mode = variable
+ x.mode_ = variable
x.typ_ = typ.elem
case *Map:
index := check.singleIndex(e)
if index == nil {
- x.mode = invalid
+ x.mode_ = invalid
return false
}
var key operand
check.expr(nil, &key, index)
check.assignment(&key, typ.key, "map index")
// ok to continue even if indexing failed - map element type is known
- x.mode = mapindex
+ x.mode_ = mapindex
x.typ_ = typ.elem
x.expr = e.orig
return false
case *Array:
l = t.len
e = t.elem
- if x.mode != variable {
+ if x.mode_ != variable {
mode = value
}
case *Pointer:
if key != nil {
index := check.singleIndex(e)
if index == nil {
- x.mode = invalid
+ x.mode_ = invalid
return false
}
var k operand
check.expr(nil, &k, index)
check.assignment(&k, key, "map index")
// ok to continue even if indexing failed - map element type is known
- x.mode = mapindex
+ x.mode_ = mapindex
x.typ_ = elem
x.expr = e.orig
return false
// no maps
valid = true
- x.mode = mode
+ x.mode_ = mode
x.typ_ = elem
}
}
// types2 uses the position of '[' for the error
check.errorf(x, NonIndexableOperand, "cannot index %s", x)
check.use(e.indices...)
- x.mode = invalid
+ x.mode_ = invalid
return false
}
index := check.singleIndex(e)
if index == nil {
- x.mode = invalid
+ x.mode_ = invalid
return false
}
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
}
// However, if x.typ is a pointer to an array type, slicing implicitly dereferences the value, meaning
// its base type must also be complete.
if p, ok := x.typ_.Underlying().(*Pointer); ok && !check.isComplete(p.base) {
- x.mode = invalid
+ x.mode_ = invalid
return
}
switch u := cu.(type) {
case nil:
// error reported above
- x.mode = invalid
+ x.mode_ = invalid
return
case *Basic:
at = e // e.Index[2] should be present but be careful
}
check.error(at, InvalidSliceExpr, invalidOp+"3-index slice of string")
- x.mode = invalid
+ x.mode_ = invalid
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
+ x.mode_ = invalid
return
}
x.typ_ = &Slice{elem: u.elem}
if !valid {
check.errorf(x, NonSliceableOperand, "cannot slice %s", x)
- x.mode = invalid
+ x.mode_ = invalid
return
}
- x.mode = value
+ x.mode_ = value
// spec: "Only the first index may be omitted; it defaults to 0."
if e.Slice3 && (e.High == nil || e.Max == nil) {
check.error(inNode(e, e.Rbrack), InvalidSyntaxTree, "2nd and 3rd index required in 3-index slice")
- x.mode = invalid
+ 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.
const limit = 10000
if len(e.Value) > limit {
check.errorf(e, InvalidConstVal, "excessively long constant: %s... (%d chars)", e.Value[:10], len(e.Value))
- x.mode = invalid
+ x.mode_ = invalid
return
}
}
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)
// should return an error describing the issue.
check.errorf(e, InvalidConstVal, "malformed constant: %s", e.Value)
- x.mode = invalid
+ x.mode_ = invalid
return
}
// Ensure that integer values don't overflow (go.dev/issue/54280).
check.funcBody(decl, "<function literal>", sig, e.Body, iota)
}).describef(e, "func literal")
}
- x.mode = value
+ x.mode_ = value
x.typ_ = sig
} else {
check.errorf(e, InvalidSyntaxTree, "invalid function literal %v", e)
- x.mode = invalid
+ x.mode_ = invalid
}
}
// We cannot create a literal of an incomplete type; make sure it's complete.
if !check.isComplete(base) {
- x.mode = invalid
+ x.mode_ = invalid
return
}
}
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 {
cause = " (no common underlying type)"
}
check.errorf(e, InvalidLit, "invalid composite literal%s type %s%s", qualifier, typ, cause)
- x.mode = invalid
+ x.mode_ = invalid
return
}
}
- x.mode = value
+ x.mode_ = value
x.typ_ = typ
}
// for built-in functions.
// The zero value of operand is a ready to use invalid operand.
type operand struct {
- mode operandMode
- expr ast.Expr
- typ_ Type
- val constant.Value
- id builtinId
+ mode_ operandMode
+ expr ast.Expr
+ typ_ Type
+ val constant.Value
+ id builtinId
}
// 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)
val := makeFromLiteral(lit, k)
if val.Kind() == constant.Unknown {
- x.mode = invalid
+ x.mode_ = invalid
x.typ_ = Typ[Invalid]
return
}
- x.mode = constant_
+ x.mode_ = constant_
x.typ_ = Typ[kind]
x.val = val
}
// 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.
// (and thus side-effects will not be computed
// by the backend).
check.record(&operand{
- mode: constant_,
- expr: rangeVar,
- typ_: Typ[Int],
- val: constant.MakeInt64(t.len),
- id: x.id,
+ mode_: constant_,
+ expr: rangeVar,
+ typ_: Typ[Int],
+ val: constant.MakeInt64(t.len),
+ id: x.id,
})
}
}
// 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)
})
check.initVar(obj, &x, "range clause")
} else {
var y operand
- y.mode = value
+ y.mode_ = value
y.expr = lhs // we don't have a better rhs expression to use here
y.typ_ = typ
check.initVar(obj, &y, "assignment") // error is on variable, use "assignment" not "range clause"
// 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 {
var y operand
- y.mode = value
+ y.mode_ = value
y.expr = lhs // we don't have a better rhs expression to use here
y.typ_ = typ
check.assignVar(lhs, nil, &y, "assignment") // error is on variable, use "assignment" not "range clause"
// 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
+ x.mode_ = invalid
}
} else {
// spec: "A missing switch expression is
// equivalent to the boolean value true."
- x.mode = constant_
+ x.mode_ = constant_
x.typ_ = Typ[Bool]
x.val = constant.MakeBool(true)
x.expr = &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"}
{
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")
}
}
// If an error occurred, x.mode is set to invalid.
// If wantType is set, the identifier e is expected to denote a type.
func (check *Checker) ident(x *operand, e *ast.Ident, wantType bool) {
- x.mode = invalid
+ x.mode_ = invalid
x.expr = e
scope, obj := check.lookupScope(e.Name)
x.val = obj.val
}
assert(x.val != nil)
- x.mode = constant_
+ x.mode_ = constant_
case *TypeName:
- x.mode = typexpr
+ x.mode_ = typexpr
case *Var:
// It's ok to mark non-local variables, but ignore variables
if !isValid(typ) {
return
}
- x.mode = variable
+ x.mode_ = variable
case *Func:
check.addDeclDep(obj)
- x.mode = value
+ x.mode_ = value
case *Builtin:
x.id = obj.id
- x.mode = builtin
+ x.mode_ = builtin
case *Nil:
- x.mode = value
+ x.mode_ = value
default:
panic("unreachable")
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