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:
parent
5f872db5fc
commit
5914f6a482
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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}
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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}
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user