1
0
mirror of https://github.com/golang/go synced 2024-11-18 17:54:57 -07:00

go/types, types2: introduce isValid predicate and use throughout

Preparation for Alias type nodes. Using a predicate will ensure
that alias indirection can be taken care of when needed, eventually.

Change-Id: I689fab6052060eb6bcb2eeac28ba09fdb73f6868
Reviewed-on: https://go-review.googlesource.com/c/go/+/528695
Reviewed-by: Heschi Kreinick <heschi@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
This commit is contained in:
Robert Griesemer 2023-09-14 18:02:41 -07:00 committed by Gopher Robot
parent 5f872db5fc
commit 5914f6a482
40 changed files with 93 additions and 87 deletions

View File

@ -458,7 +458,7 @@ func (conf *Config) Check(path string, files []*syntax.File, info *Info) (*Packa
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)
@ -496,7 +496,7 @@ func Implements(V Type, T *Interface) bool {
}
// 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)

View File

@ -102,7 +102,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
}
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]
}
@ -137,7 +137,7 @@ func (check *Checker) initConst(lhs *Const, x *operand) {
// 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]
}
@ -202,7 +202,7 @@ func (check *Checker) lhsVar(lhs syntax.Expr) Type {
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]
}
@ -234,7 +234,7 @@ func (check *Checker) lhsVar(lhs syntax.Expr) Type {
// 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 {
@ -282,7 +282,7 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string {
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) {

View File

@ -206,7 +206,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
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
@ -490,7 +490,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
// (no argument evaluated yet)
arg0 := argList[0]
T := check.varType(arg0)
if T == Typ[Invalid] {
if !isValid(T) {
return
}
@ -600,7 +600,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
// new(T)
// (no argument evaluated yet)
T := check.varType(argList[0])
if T == Typ[Invalid] {
if !isValid(T) {
return
}

View File

@ -792,7 +792,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *Named, w
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
}

View File

@ -170,7 +170,7 @@ func (check *Checker) validAlias(alias *TypeName, typ Type) {
// 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) {
@ -503,7 +503,7 @@ func (check *Checker) recordTypeAndValue(x syntax.Expr, mode operandMode, typ Ty
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}

View File

@ -387,7 +387,7 @@ func (check *Checker) constDecl(obj *Const, typ, init syntax.Expr, inherited boo
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]

View File

@ -392,7 +392,7 @@ func (check *Checker) updateExprVal(x syntax.Expr, val constant.Value) {
// 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
@ -474,7 +474,7 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const
// 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
}
@ -828,7 +828,7 @@ func (check *Checker) binary(x *operand, e syntax.Expr, lhs, rhs syntax.Expr, op
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 {
@ -1308,7 +1308,7 @@ func (check *Checker) exprInternal(T Type, x *operand, e syntax.Expr, hint Type)
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
}
@ -1363,7 +1363,7 @@ func (check *Checker) exprInternal(T Type, x *operand, e syntax.Expr, hint Type)
goto Error
}
T := check.varType(e.Type)
if T == Typ[Invalid] {
if !isValid(T) {
goto Error
}
check.typeAssertion(e, x, T, false)

View File

@ -29,7 +29,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
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
@ -428,7 +428,7 @@ func (check *Checker) indexedElts(elts []syntax.Expr, typ Type, length int64) in
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

View File

@ -192,10 +192,10 @@ func (check *Checker) verify(pos syntax.Pos, tparams []*TypeParam, targs []Type,
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)
}

View File

@ -143,7 +143,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType
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

View File

@ -172,7 +172,7 @@ func operandString(x *operand, qf Qualifier) string {
// <typ>
if hasType {
if x.typ != Typ[Invalid] {
if isValid(x.typ) {
var intro string
if isGeneric(x.typ) {
intro = " of generic type "
@ -245,7 +245,7 @@ func (x *operand) isNil() bool { return x.mode == nilvalue }
// 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
}

View File

@ -6,6 +6,9 @@
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.
@ -222,7 +225,7 @@ func (c *comparer) identical(x, y Type, p *ifacePair) bool {
return true
}
if c.ignoreInvalids && (x == Typ[Invalid] || y == Typ[Invalid]) {
if c.ignoreInvalids && (!isValid(x) || !isValid(y)) {
return true
}

View File

@ -208,7 +208,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
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

View File

@ -297,7 +297,7 @@ L:
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
}
}
@ -341,7 +341,7 @@ 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)

View File

@ -147,7 +147,7 @@ func (check *Checker) structType(styp *Struct, e *syntax.StructType) {
t, isPtr := deref(embeddedTyp)
switch u := under(t).(type) {
case *Basic:
if t == Typ[Invalid] {
if !isValid(t) {
// error was reported before
return
}

View File

@ -108,7 +108,7 @@ func (t *TypeParam) iface() *Interface {
var ityp *Interface
switch u := under(bound).(type) {
case *Basic:
if u == Typ[Invalid] {
if !isValid(u) {
// error is reported elsewhere
return &emptyInterface
}

View File

@ -290,7 +290,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
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) {
@ -389,7 +389,7 @@ func computeUnionTypeSet(check *Checker, unionSets map[*Union]*_TypeSet, pos syn
// 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) {

View File

@ -78,7 +78,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType boo
case *Const:
check.addDeclDep(obj)
if typ == Typ[Invalid] {
if !isValid(typ) {
return
}
if obj == universeIota {
@ -108,7 +108,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType boo
obj.used = true
}
check.addDeclDep(obj)
if typ == Typ[Invalid] {
if !isValid(typ) {
return
}
x.mode = variable
@ -193,7 +193,7 @@ func (check *Checker) definedType(e syntax.Expr, def *Named) Type {
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)
}
@ -323,7 +323,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
// 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
@ -416,7 +416,7 @@ func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def *
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
}
@ -520,7 +520,7 @@ func (check *Checker) typeList(list []syntax.Expr) []Type {
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 {

View File

@ -66,7 +66,7 @@ func parseUnion(check *Checker, uexpr syntax.Expr) Type {
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]
}
@ -80,7 +80,7 @@ func parseUnion(check *Checker, uexpr syntax.Expr) Type {
}
}
if u == Typ[Invalid] {
if !isValid(u) {
return u
}
@ -89,7 +89,7 @@ func parseUnion(check *Checker, uexpr syntax.Expr) Type {
// 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
}

View File

@ -68,7 +68,7 @@ func (check *Checker) validType0(typ Type, nest, path []*Named) bool {
// 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
}

View File

@ -446,7 +446,7 @@ func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, i
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)
@ -484,7 +484,7 @@ func Implements(V Type, T *Interface) bool {
}
// 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)

View File

@ -101,7 +101,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
}
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]
}
@ -136,7 +136,7 @@ func (check *Checker) initConst(lhs *Const, x *operand) {
// 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]
}
@ -201,7 +201,7 @@ func (check *Checker) lhsVar(lhs ast.Expr) Type {
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]
}
@ -233,7 +233,7 @@ func (check *Checker) lhsVar(lhs ast.Expr) Type {
// 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 {
@ -281,7 +281,7 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string {
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) {

View File

@ -205,7 +205,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
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
@ -489,7 +489,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// (no argument evaluated yet)
arg0 := argList[0]
T := check.varType(arg0)
if T == Typ[Invalid] {
if !isValid(T) {
return
}
@ -599,7 +599,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// new(T)
// (no argument evaluated yet)
T := check.varType(argList[0])
if T == Typ[Invalid] {
if !isValid(T) {
return
}

View File

@ -795,7 +795,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *Named, want
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
}

View File

@ -172,7 +172,7 @@ func (check *Checker) validAlias(alias *TypeName, typ Type) {
// 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) {
@ -512,7 +512,7 @@ func (check *Checker) recordTypeAndValue(x ast.Expr, mode operandMode, typ Type,
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}

View File

@ -456,7 +456,7 @@ func (check *Checker) constDecl(obj *Const, typ, init ast.Expr, inherited bool)
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]

View File

@ -356,7 +356,7 @@ func (check *Checker) updateExprVal(x ast.Expr, val constant.Value) {
// 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
@ -452,7 +452,7 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const
// 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
}
@ -810,7 +810,7 @@ func (check *Checker) binary(x *operand, e ast.Expr, lhs, rhs ast.Expr, op token
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
@ -1290,7 +1290,7 @@ func (check *Checker) exprInternal(T Type, x *operand, e ast.Expr, hint Type) ex
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
}
@ -1348,7 +1348,7 @@ func (check *Checker) exprInternal(T Type, x *operand, e ast.Expr, hint Type) ex
goto Error
}
T := check.varType(e.Type)
if T == Typ[Invalid] {
if !isValid(T) {
goto Error
}
check.typeAssertion(e, x, T, false)

View File

@ -30,7 +30,7 @@ func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst
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
@ -421,7 +421,7 @@ func (check *Checker) indexedElts(elts []ast.Expr, typ Type, length int64) int64
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

View File

@ -194,10 +194,10 @@ func (check *Checker) verify(pos token.Pos, tparams []*TypeParam, targs []Type,
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)
}

View File

@ -182,7 +182,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
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

View File

@ -159,7 +159,7 @@ func operandString(x *operand, qf Qualifier) string {
// <typ>
if hasType {
if x.typ != Typ[Invalid] {
if isValid(x.typ) {
var intro string
if isGeneric(x.typ) {
intro = " of generic type "
@ -232,7 +232,7 @@ func (x *operand) isNil() bool { return x.mode == value && x.typ == Typ[UntypedN
// 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
}

View File

@ -8,6 +8,9 @@
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.
@ -224,7 +227,7 @@ func (c *comparer) identical(x, y Type, p *ifacePair) bool {
return true
}
if c.ignoreInvalids && (x == Typ[Invalid] || y == Typ[Invalid]) {
if c.ignoreInvalids && (!isValid(x) || !isValid(y)) {
return true
}

View File

@ -211,7 +211,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
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

View File

@ -291,7 +291,7 @@ L:
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
}
}
@ -332,7 +332,7 @@ 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)

View File

@ -146,7 +146,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType) {
t, isPtr := deref(embeddedTyp)
switch u := under(t).(type) {
case *Basic:
if t == Typ[Invalid] {
if !isValid(t) {
// error was reported before
return
}

View File

@ -110,7 +110,7 @@ func (t *TypeParam) iface() *Interface {
var ityp *Interface
switch u := under(bound).(type) {
case *Basic:
if u == Typ[Invalid] {
if !isValid(u) {
// error is reported elsewhere
return &emptyInterface
}

View File

@ -288,7 +288,7 @@ func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_T
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) {
@ -387,7 +387,7 @@ func computeUnionTypeSet(check *Checker, unionSets map[*Union]*_TypeSet, pos tok
// 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) {

View File

@ -79,7 +79,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool)
case *Const:
check.addDeclDep(obj)
if typ == Typ[Invalid] {
if !isValid(typ) {
return
}
if obj == universeIota {
@ -109,7 +109,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool)
obj.used = true
}
check.addDeclDep(obj)
if typ == Typ[Invalid] {
if !isValid(typ) {
return
}
x.mode = variable
@ -193,7 +193,7 @@ func (check *Checker) definedType(e ast.Expr, def *Named) Type {
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)
}
@ -407,7 +407,7 @@ func (check *Checker) instantiatedType(ix *typeparams.IndexExpr, def *Named) (re
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
}
@ -511,7 +511,7 @@ func (check *Checker) typeList(list []ast.Expr) []Type {
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 {

View File

@ -67,7 +67,7 @@ func parseUnion(check *Checker, uexpr ast.Expr) Type {
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]
}
@ -81,7 +81,7 @@ func parseUnion(check *Checker, uexpr ast.Expr) Type {
}
}
if u == Typ[Invalid] {
if !isValid(u) {
return u
}
@ -90,7 +90,7 @@ func parseUnion(check *Checker, uexpr ast.Expr) Type {
// 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
}

View File

@ -70,7 +70,7 @@ func (check *Checker) validType0(typ Type, nest, path []*Named) bool {
// 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
}