func (tc *typechecker) resolve(obj *ast.Object) {
	// check for declaration cycles
	if tc.cyclemap[obj] {
		tc.Errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name)
		obj.Kind = ast.Bad
		return
	}
	tc.cyclemap[obj] = true
	defer func() {
		delete(tc.cyclemap, obj)
	}()

	// resolve non-type objects
	typ, _ := obj.Type.(*Type)
	if typ == nil {
		switch obj.Kind {
		case ast.Bad:
			// ignore

		case ast.Con:
			tc.declConst(obj)

		case ast.Var:
			tc.declVar(obj)
			obj.Type = tc.typeFor(nil, obj.Decl.(*ast.ValueSpec).Type, false)

		case ast.Fun:
			obj.Type = NewType(Function)
			t := obj.Decl.(*ast.FuncDecl).Type
			tc.declSignature(obj.Type.(*Type), nil, t.Params, t.Results)

		default:
			// type objects have non-nil types when resolve is called
			if debug {
				fmt.Printf("kind = %s\n", obj.Kind)
			}
			panic("unreachable")
		}
		return
	}

	// resolve type objects
	if typ.Form == Unresolved {
		tc.typeFor(typ, typ.Obj.Decl.(*ast.TypeSpec).Type, false)

		// provide types for all methods
		for _, obj := range typ.Scope.Objects {
			if obj.Kind == ast.Fun {
				assert(obj.Type == nil)
				obj.Type = NewType(Method)
				f := obj.Decl.(*ast.FuncDecl)
				t := f.Type
				tc.declSignature(obj.Type.(*Type), f.Recv, t.Params, t.Results)
			}
		}
	}
}
// checkObj type checks an object.
func (c *checker) checkObj(obj *ast.Object, ref bool) {
	if obj.Type != nil {
		// object has already been type checked
		return
	}

	switch obj.Kind {
	case ast.Bad:
		// ignore

	case ast.Con:
		// TODO(gri) complete this

	case ast.Typ:
		typ := &Name{Obj: obj}
		obj.Type = typ // "mark" object so recursion terminates
		typ.Underlying = Underlying(c.makeType(obj.Decl.(*ast.TypeSpec).Type, ref))

	case ast.Var:
		// TODO(gri) complete this

	case ast.Fun:
		// TODO(gri) complete this

	default:
		panic("unreachable")
	}
}