return obj
}
-// pathString returns a string of the form a->b-> ... ->g for an object path [a, b, ... g].
-func (check *Checker) pathString() string {
- return objPathString(check.objPath)
-}
-
// NewChecker returns a new Checker instance for a given package.
// Package files may be added incrementally via checker.Files.
func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Checker {
// objDecl type-checks the declaration of obj in its respective (file) context.
// See check.typ for the details on def and path.
-func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
+func (check *Checker) objDecl(obj Object, def *Named) {
if trace {
- check.trace(obj.Pos(), "-- checking %s %s (path = %s, objPath = %s)", obj.color(), obj, pathString(path), check.pathString())
+ check.trace(obj.Pos(), "-- checking %s %s (objPath = %s)", obj.color(), obj, objPathString(check.objPath))
check.indent++
defer func() {
check.indent--
check.varDecl(obj, d.lhs, d.typ, d.init)
case *TypeName:
// invalid recursive types are detected via path
- check.typeDecl(obj, d.typ, def, path, d.alias)
+ check.typeDecl(obj, d.typ, def, d.alias)
case *Func:
// functions may be recursive - no need to track dependencies
check.funcDecl(obj, d)
// determine type, if any
if typ != nil {
- t := check.typExpr(typ, nil, nil)
+ t := check.typExpr(typ, nil)
if !isConstType(t) {
// don't report an error if the type is an invalid C (defined) type
// (issue #22090)
// determine type, if any
if typ != nil {
- obj.typ = check.typExpr(typ, nil, nil)
+ obj.typ = check.typExpr(typ, nil)
// We cannot spread the type to all lhs variables if there
// are more than one since that would mark them as checked
// (see Checker.objDecl) and the assignment of init exprs,
}
}
-func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName, alias bool) {
+func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, alias bool) {
assert(obj.typ == nil)
if alias {
obj.typ = Typ[Invalid]
- obj.typ = check.typExpr(typ, nil, append(path, obj))
+ obj.typ = check.typExpr(typ, nil)
} else {
obj.typ = named // make sure recursive type declarations terminate
// determine underlying type of named
- check.typExpr(typ, named, append(path, obj))
+ check.typExpr(typ, named)
// The underlying type of named may be itself a named type that is
// incomplete:
}
// type-check
- check.objDecl(m, nil, nil)
+ check.objDecl(m, nil)
if base != nil {
base.methods = append(base.methods, m)
check.declare(check.scope, s.Name, obj, scopePos)
// mark and unmark type before calling typeDecl; its type is still nil (see Checker.objDecl)
obj.setColor(grey + color(check.push(obj)))
- check.typeDecl(obj, s.Type, nil, nil, s.Assign.IsValid())
+ check.typeDecl(obj, s.Type, nil, s.Assign.IsValid())
check.pop().setColor(black)
default:
check.invalidAST(s.Pos(), "const, type, or var declaration expected")
goto Error // error was reported before
case *ast.Ident:
- check.ident(x, e, nil, nil)
+ check.ident(x, e, nil)
case *ast.Ellipsis:
// ellipses are handled explicitly where they are legal
break
}
}
- typ = check.typExpr(e.Type, nil, nil)
+ typ = check.typExpr(e.Type, nil)
base = typ
case hint != nil:
check.invalidAST(e.Pos(), "use of .(type) outside type switch")
goto Error
}
- T := check.typExpr(e.Type, nil, nil)
+ T := check.typExpr(e.Type, nil)
if T == Typ[Invalid] {
goto Error
}
}
if trace {
- check.trace(iface.Pos(), "-- collect methods for %v (path = %s, objPath = %s)", iface, pathString(path), check.pathString())
+ check.trace(iface.Pos(), "-- collect methods for %v (path = %s, objPath = %s)", iface, pathString(path), objPathString(check.objPath))
check.indent++
defer func() {
check.indent--
}
}
+// cycle reports whether obj appears in path or not.
+// If it does, and report is set, it also reports a cycle error.
+func (check *Checker) cycle(obj *TypeName, path []*TypeName, report bool) bool {
+ // (it's ok to iterate forward because each named type appears at most once in path)
+ for i, prev := range path {
+ if prev == obj {
+ if report {
+ check.errorf(obj.pos, "illegal cycle in declaration of %s", obj.name)
+ // print cycle
+ for _, obj := range path[i:] {
+ check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
+ }
+ check.errorf(obj.Pos(), "\t%s", obj.Name())
+ }
+ return true
+ }
+ }
+ return false
+}
+
// packageObjects typechecks all package objects, but not function bodies.
func (check *Checker) packageObjects() {
// process package objects in source order for reproducible results
}
}
- // pre-allocate space for type declaration paths so that the underlying array is reused
- typePath := make([]*TypeName, 0, 8)
-
for _, obj := range objList {
- check.objDecl(obj, nil, typePath)
+ check.objDecl(obj, nil)
}
// At this point we may have a non-empty check.methods map; this means that not all
// ident type-checks identifier e and initializes x with the value or type of e.
// If an error occurred, x.mode is set to invalid.
-// For the meaning of def and path, see check.typ, below.
+// For the meaning of def, see check.typExpr, below.
//
-func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeName) {
+func (check *Checker) ident(x *operand, e *ast.Ident, def *Named) {
x.mode = invalid
x.expr = e
}
check.recordUse(e, obj)
- check.objDecl(obj, def, path)
+ check.objDecl(obj, def)
typ := obj.Type()
assert(typ != nil)
x.typ = typ
}
-// cycle reports whether obj appears in path or not.
-// If it does, and report is set, it also reports a cycle error.
-func (check *Checker) cycle(obj *TypeName, path []*TypeName, report bool) bool {
- // (it's ok to iterate forward because each named type appears at most once in path)
- for i, prev := range path {
- if prev == obj {
- if report {
- check.errorf(obj.pos, "illegal cycle in declaration of %s", obj.name)
- // print cycle
- for _, obj := range path[i:] {
- check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
- }
- check.errorf(obj.Pos(), "\t%s", obj.Name())
- }
- return true
- }
- }
- return false
-}
-
// typExpr type-checks the type expression e and returns its type, or Typ[Invalid].
// If def != nil, e is the type specification for the named type def, declared
// in a type declaration, and def.underlying will be set to the type of e before
-// any components of e are type-checked. Path contains the path of named types
-// referring to this type; i.e. it is the path of named types directly containing
-// each other and leading to the current type e. Indirect containment (e.g. via
-// pointer indirection, function parameter, etc.) breaks the path (leads to a new
-// path, and usually via calling Checker.typ below) and those types are not found
-// in the path.
+// any components of e are type-checked.
//
-func (check *Checker) typExpr(e ast.Expr, def *Named, path []*TypeName) (T Type) {
+func (check *Checker) typExpr(e ast.Expr, def *Named) (T Type) {
if trace {
check.trace(e.Pos(), "%s", e)
check.indent++
}()
}
- T = check.typExprInternal(e, def, path)
+ T = check.typExprInternal(e, def)
assert(isTyped(T))
check.recordTypeAndValue(e, typexpr, T, nil)
// element types, etc. See the comment in typExpr for details.
//
func (check *Checker) typ(e ast.Expr) Type {
- // typExpr is called with a nil path indicating an indirection:
- // push indir sentinel on object path
+ // push indir sentinel on object path to indicate an indirection
check.push(indir)
defer check.pop()
- return check.typExpr(e, nil, nil)
+ return check.typExpr(e, nil)
}
// funcType type-checks a function or method type.
// typExprInternal drives type checking of types.
// Must only be called by typExpr.
//
-func (check *Checker) typExprInternal(e ast.Expr, def *Named, path []*TypeName) Type {
+func (check *Checker) typExprInternal(e ast.Expr, def *Named) Type {
switch e := e.(type) {
case *ast.BadExpr:
// ignore - error reported before
case *ast.Ident:
var x operand
- check.ident(&x, e, def, path)
+ check.ident(&x, e, def)
switch x.mode {
case typexpr:
}
case *ast.ParenExpr:
- return check.typExpr(e.X, def, path)
+ return check.typExpr(e.X, def)
case *ast.ArrayType:
if e.Len != nil {
typ := new(Array)
def.setUnderlying(typ)
typ.len = check.arrayLength(e.Len)
- typ.elem = check.typExpr(e.Elt, nil, path)
+ typ.elem = check.typExpr(e.Elt, nil)
return typ
} else {
case *ast.StructType:
typ := new(Struct)
def.setUnderlying(typ)
- check.structType(typ, e, path)
+ check.structType(typ, e)
return typ
case *ast.StarExpr:
case *ast.InterfaceType:
typ := new(Interface)
def.setUnderlying(typ)
- check.interfaceType(typ, e, def, path)
+ check.interfaceType(typ, e, def)
return typ
case *ast.MapType:
return true
}
-func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named, path []*TypeName) {
+func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named) {
// fast-track empty interface
if iface.Methods.List == nil {
ityp.allMethods = markComplete
// compute method set
var tname *TypeName
+ var path []*TypeName
if def != nil {
tname = def.obj
+ path = []*TypeName{tname}
}
info := check.infoFromTypeLit(check.scope, iface, tname, path)
if info == nil || info == &emptyIfaceInfo {
return ""
}
-func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeName) {
+func (check *Checker) structType(styp *Struct, e *ast.StructType) {
list := e.Fields
if list == nil {
return
}
for _, f := range list.List {
- typ = check.typExpr(f.Type, nil, path)
+ typ = check.typExpr(f.Type, nil)
tag = check.tag(f.Tag)
if len(f.Names) > 0 {
// named fields