func AssertableTo(V *Interface, T Type) bool {
// Checker.newAssertableTo suppresses errors for invalid types, so we need special
// handling here.
- if T.Underlying() == Typ[Invalid] {
+ if !isValid(T.Underlying()) {
return false
}
return (*Checker)(nil).newAssertableTo(nopos, V, T, nil)
}
// Checker.implements suppresses errors for invalid types, so we need special
// handling here.
- if V.Underlying() == Typ[Invalid] {
+ if !isValid(V.Underlying()) {
return false
}
return (*Checker)(nil).implements(nopos, V, T, false, nil)
}
func (check *Checker) initConst(lhs *Const, x *operand) {
- if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
+ if x.mode == invalid || !isValid(x.typ) || !isValid(lhs.typ) {
if lhs.typ == nil {
lhs.typ = Typ[Invalid]
}
// 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 || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
+ if x.mode == invalid || !isValid(x.typ) || !isValid(lhs.typ) {
if lhs.typ == nil {
lhs.typ = Typ[Invalid]
}
v.used = v_used // restore v.used
}
- if x.mode == invalid || x.typ == Typ[Invalid] {
+ if x.mode == invalid || !isValid(x.typ) {
return Typ[Invalid]
}
// If the assignment check fails and x != nil, x.mode is set to invalid.
func (check *Checker) assignVar(lhs, rhs syntax.Expr, x *operand) {
T := check.lhsVar(lhs) // nil if lhs is _
- if T == Typ[Invalid] {
+ if !isValid(T) {
if x != nil {
x.mode = invalid
} else {
switch {
case t == nil:
fallthrough // should not happen but be cautious
- case t == Typ[Invalid]:
+ case !isValid(t):
s = "unknown type"
case isUntyped(t):
if isNumeric(t) {
if mode == invalid {
// avoid error if underlying type is invalid
- if under(x.typ) != Typ[Invalid] {
+ if isValid(under(x.typ)) {
code := InvalidCap
if id == _Len {
code = InvalidLen
// (no argument evaluated yet)
arg0 := argList[0]
T := check.varType(arg0)
- if T == Typ[Invalid] {
+ if !isValid(T) {
return
}
// new(T)
// (no argument evaluated yet)
T := check.varType(argList[0])
- if T == Typ[Invalid] {
+ if !isValid(T) {
return
}
obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
if obj == nil {
// Don't report another error if the underlying type was invalid (go.dev/issue/49541).
- if under(x.typ) == Typ[Invalid] {
+ if !isValid(under(x.typ)) {
goto Error
}
// isBrokenAlias reports whether alias doesn't have a determined type yet.
func (check *Checker) isBrokenAlias(alias *TypeName) bool {
- return alias.typ == Typ[Invalid] && check.brokenAliases[alias]
+ return !isValid(alias.typ) && check.brokenAliases[alias]
}
func (check *Checker) rememberUntyped(e syntax.Expr, lhs bool, mode operandMode, typ *Basic, val constant.Value) {
assert(val != nil)
// We check allBasic(typ, IsConstType) here as constant expressions may be
// recorded as type parameters.
- assert(typ == Typ[Invalid] || allBasic(typ, IsConstType))
+ assert(!isValid(typ) || allBasic(typ, IsConstType))
}
if m := check.Types; m != nil {
m[x] = TypeAndValue{mode, typ, val}
if !isConstType(t) {
// don't report an error if the type is an invalid C (defined) type
// (go.dev/issue/22090)
- if under(t) != Typ[Invalid] {
+ if isValid(under(t)) {
check.errorf(typ, InvalidConstType, "invalid constant type %s", t)
}
obj.typ = Typ[Invalid]
// 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) || target == Typ[Invalid] {
+ if x.mode == invalid || isTyped(x.typ) || !isValid(target) {
return x.typ, nil, 0
}
// x is untyped
// If switchCase is true, the operator op is ignored.
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 x.typ == Typ[Invalid] || y.typ == Typ[Invalid] {
+ if !isValid(x.typ) || !isValid(y.typ) {
x.mode = invalid
return
}
if !Identical(x.typ, y.typ) {
// only report an error if we have valid types
// (otherwise we had an error reported elsewhere already)
- if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] {
+ if isValid(x.typ) && isValid(y.typ) {
if e != nil {
check.errorf(x, MismatchedTypes, invalidOp+"%s (mismatched types %s and %s)", e, x.typ, y.typ)
} else {
check.use(e)
}
// if utyp is invalid, an error was reported before
- if utyp != Typ[Invalid] {
+ if isValid(utyp) {
check.errorf(e, InvalidLit, "invalid composite literal type %s", typ)
goto Error
}
goto Error
}
T := check.varType(e.Type)
- if T == Typ[Invalid] {
+ if !isValid(T) {
goto Error
}
check.typeAssertion(e, x, T, false)
x.mode = invalid
// TODO(gri) here we re-evaluate e.X - try to avoid this
x.typ = check.varType(e)
- if x.typ != Typ[Invalid] {
+ if isValid(x.typ) {
x.mode = typexpr
}
return false
validIndex := false
eval := e
if kv, _ := e.(*syntax.KeyValueExpr); kv != nil {
- if typ, i := check.index(kv.Key, length); typ != Typ[Invalid] {
+ if typ, i := check.index(kv.Key, length); isValid(typ) {
if i >= 0 {
index = i
validIndex = true
func (check *Checker) implements(pos syntax.Pos, V, T Type, constraint bool, cause *string) bool {
Vu := under(V)
Tu := under(T)
- if Vu == Typ[Invalid] || Tu == Typ[Invalid] {
+ if !isValid(Vu) || !isValid(Tu) {
return true // avoid follow-on errors
}
- if p, _ := Vu.(*Pointer); p != nil && under(p.base) == Typ[Invalid] {
+ if p, _ := Vu.(*Pointer); p != nil && !isValid(under(p.base)) {
return true // avoid follow-on errors (see go.dev/issue/49541 for an example)
}
typ := check.typ(f.Type)
sig, _ := typ.(*Signature)
if sig == nil {
- if typ != Typ[Invalid] {
+ if isValid(typ) {
check.errorf(f.Type, InvalidSyntaxTree, "%s is not a method signature", typ)
}
continue // ignore
// <typ>
if hasType {
- if x.typ != Typ[Invalid] {
+ if isValid(x.typ) {
var intro string
if isGeneric(x.typ) {
intro = " of generic type "
// 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 || T == Typ[Invalid] {
+ if x.mode == invalid || !isValid(T) {
return true, 0 // avoid spurious errors
}
package types2
+// isValid reports whether t is a valid type.
+func isValid(t Type) bool { return t != Typ[Invalid] }
+
// The isX predicates below report whether t is an X.
// If t is a type parameter the result is false; i.e.,
// these predicates don't look inside a type parameter.
return true
}
- if c.ignoreInvalids && (x == Typ[Invalid] || y == Typ[Invalid]) {
+ if c.ignoreInvalids && (!isValid(x) || !isValid(y)) {
return true
}
check.later(func() {
// spec: "The receiver type must be of the form T or *T where T is a type name."
rtyp, _ := deref(recv.typ)
- if rtyp == Typ[Invalid] {
+ if !isValid(rtyp) {
return // error was reported before
}
// spec: "The type denoted by T is called the receiver base type; it must not
check.expr(nil, &dummy, e) // run e through expr so we get the usual Info recordings
} else {
T = check.varType(e)
- if T == Typ[Invalid] {
+ if !isValid(T) {
continue L
}
}
// hash = "<nil>" // avoid collision with a type named nil
// } else {
// T = check.varType(e)
-// if T == Typ[Invalid] {
+// if !isValid(T) {
// continue L
// }
// hash = typeHash(T, nil)
t, isPtr := deref(embeddedTyp)
switch u := under(t).(type) {
case *Basic:
- if t == Typ[Invalid] {
+ if !isValid(t) {
// error was reported before
return
}
var ityp *Interface
switch u := under(bound).(type) {
case *Basic:
- if u == Typ[Invalid] {
+ if !isValid(u) {
// error is reported elsewhere
return &emptyInterface
}
assert(len(tset.methods) == 0)
terms = tset.terms
default:
- if u == Typ[Invalid] {
+ if !isValid(u) {
continue
}
if check != nil && !check.verifyVersionf(pos, go1_18, "embedding non-interface type %s", typ) {
// For now we don't permit type parameters as constraints.
assert(!isTypeParam(t.typ))
terms = computeInterfaceTypeSet(check, pos, ui).terms
- } else if u == Typ[Invalid] {
+ } else if !isValid(u) {
continue
} else {
if t.tilde && !Identical(t.typ, u) {
case *Const:
check.addDeclDep(obj)
- if typ == Typ[Invalid] {
+ if !isValid(typ) {
return
}
if obj == universeIota {
obj.used = true
}
check.addDeclDep(obj)
- if typ == Typ[Invalid] {
+ if !isValid(typ) {
return
}
x.mode = variable
func (check *Checker) genericType(e syntax.Expr, cause *string) Type {
typ := check.typInternal(e, nil)
assert(isTyped(typ))
- if typ != Typ[Invalid] && !isGeneric(typ) {
+ if isValid(typ) && !isGeneric(typ) {
if cause != nil {
*cause = check.sprintf("%s is not a generic type", typ)
}
// useful - even a valid dereferenciation will lead to an invalid
// type again, and in some cases we get unexpected follow-on errors
// (e.g., go.dev/issue/49005). Return an invalid type instead.
- if typ.base == Typ[Invalid] {
+ if !isValid(typ.base) {
return Typ[Invalid]
}
return typ
if cause != "" {
check.errorf(x, NotAGenericType, invalidOp+"%s%s (%s)", x, xlist, cause)
}
- if gtyp == Typ[Invalid] {
+ if !isValid(gtyp) {
return gtyp // error already reported
}
res := make([]Type, len(list)) // res != nil even if len(list) == 0
for i, x := range list {
t := check.varType(x)
- if t == Typ[Invalid] {
+ if !isValid(t) {
res = nil
}
if res != nil {
return term.typ // typ already recorded through check.typ in parseTilde
}
if len(terms) >= maxTermCount {
- if u != Typ[Invalid] {
+ if isValid(u) {
check.errorf(x, InvalidUnion, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
u = Typ[Invalid]
}
}
}
- if u == Typ[Invalid] {
+ if !isValid(u) {
return u
}
// Note: This is a quadratic algorithm, but unions tend to be short.
check.later(func() {
for i, t := range terms {
- if t.typ == Typ[Invalid] {
+ if !isValid(t.typ) {
continue
}
// Don't report a 2nd error if we already know the type is invalid
// (e.g., if a cycle was detected earlier, via under).
// Note: ensure that t.orig is fully resolved by calling Underlying().
- if t.Underlying() == Typ[Invalid] {
+ if !isValid(t.Underlying()) {
return false
}
func AssertableTo(V *Interface, T Type) bool {
// Checker.newAssertableTo suppresses errors for invalid types, so we need special
// handling here.
- if T.Underlying() == Typ[Invalid] {
+ if !isValid(T.Underlying()) {
return false
}
return (*Checker)(nil).newAssertableTo(nopos, V, T, nil)
}
// Checker.implements suppresses errors for invalid types, so we need special
// handling here.
- if V.Underlying() == Typ[Invalid] {
+ if !isValid(V.Underlying()) {
return false
}
return (*Checker)(nil).implements(0, V, T, false, nil)
}
func (check *Checker) initConst(lhs *Const, x *operand) {
- if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
+ if x.mode == invalid || !isValid(x.typ) || !isValid(lhs.typ) {
if lhs.typ == nil {
lhs.typ = Typ[Invalid]
}
// 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 || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
+ if x.mode == invalid || !isValid(x.typ) || !isValid(lhs.typ) {
if lhs.typ == nil {
lhs.typ = Typ[Invalid]
}
v.used = v_used // restore v.used
}
- if x.mode == invalid || x.typ == Typ[Invalid] {
+ if x.mode == invalid || !isValid(x.typ) {
return Typ[Invalid]
}
// If the assignment check fails and x != nil, x.mode is set to invalid.
func (check *Checker) assignVar(lhs, rhs ast.Expr, x *operand) {
T := check.lhsVar(lhs) // nil if lhs is _
- if T == Typ[Invalid] {
+ if !isValid(T) {
if x != nil {
x.mode = invalid
} else {
switch {
case t == nil:
fallthrough // should not happen but be cautious
- case t == Typ[Invalid]:
+ case !isValid(t):
s = "unknown type"
case isUntyped(t):
if isNumeric(t) {
if mode == invalid {
// avoid error if underlying type is invalid
- if under(x.typ) != Typ[Invalid] {
+ if isValid(under(x.typ)) {
code := InvalidCap
if id == _Len {
code = InvalidLen
// (no argument evaluated yet)
arg0 := argList[0]
T := check.varType(arg0)
- if T == Typ[Invalid] {
+ if !isValid(T) {
return
}
// new(T)
// (no argument evaluated yet)
T := check.varType(argList[0])
- if T == Typ[Invalid] {
+ if !isValid(T) {
return
}
obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
if obj == nil {
// Don't report another error if the underlying type was invalid (go.dev/issue/49541).
- if under(x.typ) == Typ[Invalid] {
+ if !isValid(under(x.typ)) {
goto Error
}
// isBrokenAlias reports whether alias doesn't have a determined type yet.
func (check *Checker) isBrokenAlias(alias *TypeName) bool {
- return alias.typ == Typ[Invalid] && check.brokenAliases[alias]
+ return !isValid(alias.typ) && check.brokenAliases[alias]
}
func (check *Checker) rememberUntyped(e ast.Expr, lhs bool, mode operandMode, typ *Basic, val constant.Value) {
assert(val != nil)
// We check allBasic(typ, IsConstType) here as constant expressions may be
// recorded as type parameters.
- assert(typ == Typ[Invalid] || allBasic(typ, IsConstType))
+ assert(!isValid(typ) || allBasic(typ, IsConstType))
}
if m := check.Types; m != nil {
m[x] = TypeAndValue{mode, typ, val}
if !isConstType(t) {
// don't report an error if the type is an invalid C (defined) type
// (go.dev/issue/22090)
- if under(t) != Typ[Invalid] {
+ if isValid(under(t)) {
check.errorf(typ, InvalidConstType, "invalid constant type %s", t)
}
obj.typ = Typ[Invalid]
// 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) || target == Typ[Invalid] {
+ if x.mode == invalid || isTyped(x.typ) || !isValid(target) {
return x.typ, nil, 0
}
// x is untyped
// If switchCase is true, the operator op is ignored.
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 x.typ == Typ[Invalid] || y.typ == Typ[Invalid] {
+ if !isValid(x.typ) || !isValid(y.typ) {
x.mode = invalid
return
}
if !Identical(x.typ, y.typ) {
// only report an error if we have valid types
// (otherwise we had an error reported elsewhere already)
- if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] {
+ if isValid(x.typ) && isValid(y.typ) {
var posn positioner = x
if e != nil {
posn = e
check.use(e)
}
// if utyp is invalid, an error was reported before
- if utyp != Typ[Invalid] {
+ if isValid(utyp) {
check.errorf(e, InvalidLit, "invalid composite literal type %s", typ)
goto Error
}
goto Error
}
T := check.varType(e.Type)
- if T == Typ[Invalid] {
+ if !isValid(T) {
goto Error
}
check.typeAssertion(e, x, T, false)
x.mode = invalid
// TODO(gri) here we re-evaluate e.X - try to avoid this
x.typ = check.varType(e.Orig)
- if x.typ != Typ[Invalid] {
+ if isValid(x.typ) {
x.mode = typexpr
}
return false
validIndex := false
eval := e
if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
- if typ, i := check.index(kv.Key, length); typ != Typ[Invalid] {
+ if typ, i := check.index(kv.Key, length); isValid(typ) {
if i >= 0 {
index = i
validIndex = true
func (check *Checker) implements(pos token.Pos, V, T Type, constraint bool, cause *string) bool {
Vu := under(V)
Tu := under(T)
- if Vu == Typ[Invalid] || Tu == Typ[Invalid] {
+ if !isValid(Vu) || !isValid(Tu) {
return true // avoid follow-on errors
}
- if p, _ := Vu.(*Pointer); p != nil && under(p.base) == Typ[Invalid] {
+ if p, _ := Vu.(*Pointer); p != nil && !isValid(under(p.base)) {
return true // avoid follow-on errors (see go.dev/issue/49541 for an example)
}
typ := check.typ(f.Type)
sig, _ := typ.(*Signature)
if sig == nil {
- if typ != Typ[Invalid] {
+ if isValid(typ) {
check.errorf(f.Type, InvalidSyntaxTree, "%s is not a method signature", typ)
}
continue // ignore
// <typ>
if hasType {
- if x.typ != Typ[Invalid] {
+ if isValid(x.typ) {
var intro string
if isGeneric(x.typ) {
intro = " of generic type "
// 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 || T == Typ[Invalid] {
+ if x.mode == invalid || !isValid(T) {
return true, 0 // avoid spurious errors
}
package types
+// isValid reports whether t is a valid type.
+func isValid(t Type) bool { return t != Typ[Invalid] }
+
// The isX predicates below report whether t is an X.
// If t is a type parameter the result is false; i.e.,
// these predicates don't look inside a type parameter.
return true
}
- if c.ignoreInvalids && (x == Typ[Invalid] || y == Typ[Invalid]) {
+ if c.ignoreInvalids && (!isValid(x) || !isValid(y)) {
return true
}
check.later(func() {
// spec: "The receiver type must be of the form T or *T where T is a type name."
rtyp, _ := deref(recv.typ)
- if rtyp == Typ[Invalid] {
+ if !isValid(rtyp) {
return // error was reported before
}
// spec: "The type denoted by T is called the receiver base type; it must not
check.expr(nil, &dummy, e) // run e through expr so we get the usual Info recordings
} else {
T = check.varType(e)
- if T == Typ[Invalid] {
+ if !isValid(T) {
continue L
}
}
// hash = "<nil>" // avoid collision with a type named nil
// } else {
// T = check.varType(e)
-// if T == Typ[Invalid] {
+// if !isValid(T) {
// continue L
// }
// hash = typeHash(T, nil)
t, isPtr := deref(embeddedTyp)
switch u := under(t).(type) {
case *Basic:
- if t == Typ[Invalid] {
+ if !isValid(t) {
// error was reported before
return
}
var ityp *Interface
switch u := under(bound).(type) {
case *Basic:
- if u == Typ[Invalid] {
+ if !isValid(u) {
// error is reported elsewhere
return &emptyInterface
}
assert(len(tset.methods) == 0)
terms = tset.terms
default:
- if u == Typ[Invalid] {
+ if !isValid(u) {
continue
}
if check != nil && !check.verifyVersionf(atPos(pos), go1_18, "embedding non-interface type %s", typ) {
// For now we don't permit type parameters as constraints.
assert(!isTypeParam(t.typ))
terms = computeInterfaceTypeSet(check, pos, ui).terms
- } else if u == Typ[Invalid] {
+ } else if !isValid(u) {
continue
} else {
if t.tilde && !Identical(t.typ, u) {
case *Const:
check.addDeclDep(obj)
- if typ == Typ[Invalid] {
+ if !isValid(typ) {
return
}
if obj == universeIota {
obj.used = true
}
check.addDeclDep(obj)
- if typ == Typ[Invalid] {
+ if !isValid(typ) {
return
}
x.mode = variable
func (check *Checker) genericType(e ast.Expr, cause *string) Type {
typ := check.typInternal(e, nil)
assert(isTyped(typ))
- if typ != Typ[Invalid] && !isGeneric(typ) {
+ if isValid(typ) && !isGeneric(typ) {
if cause != nil {
*cause = check.sprintf("%s is not a generic type", typ)
}
if cause != "" {
check.errorf(ix.Orig, NotAGenericType, invalidOp+"%s (%s)", ix.Orig, cause)
}
- if gtyp == Typ[Invalid] {
+ if !isValid(gtyp) {
return gtyp // error already reported
}
res := make([]Type, len(list)) // res != nil even if len(list) == 0
for i, x := range list {
t := check.varType(x)
- if t == Typ[Invalid] {
+ if !isValid(t) {
res = nil
}
if res != nil {
return term.typ // typ already recorded through check.typ in parseTilde
}
if len(terms) >= maxTermCount {
- if u != Typ[Invalid] {
+ if isValid(u) {
check.errorf(x, InvalidUnion, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
u = Typ[Invalid]
}
}
}
- if u == Typ[Invalid] {
+ if !isValid(u) {
return u
}
// Note: This is a quadratic algorithm, but unions tend to be short.
check.later(func() {
for i, t := range terms {
- if t.typ == Typ[Invalid] {
+ if !isValid(t.typ) {
continue
}
// Don't report a 2nd error if we already know the type is invalid
// (e.g., if a cycle was detected earlier, via under).
// Note: ensure that t.orig is fully resolved by calling Underlying().
- if t.Underlying() == Typ[Invalid] {
+ if !isValid(t.Underlying()) {
return false
}