package main // TCTypeAndValue records the type and optional constant value for an expression. type TCTypeAndValue struct { Type Type Value ConstVal // nil for non-constant expressions mode exprMode } type exprMode uint8 const ( modeInvalid exprMode = iota modeVoid // no value (statement context) modeValue // an addressable or non-addressable value modeVar // addressable variable modeConst // constant expression modeType // a type expression modeBuiltin // a builtin identifier modePkg // a package name modeNil // the predeclared nil ) func (tv TCTypeAndValue) IsValue() bool { return tv.mode == modeValue || tv.mode == modeVar || tv.mode == modeConst || tv.mode == modeNil } func (tv TCTypeAndValue) IsType() bool { return tv.mode == modeType } func (tv TCTypeAndValue) IsBuiltin() bool { return tv.mode == modeBuiltin } func (tv TCTypeAndValue) IsConst() bool { return tv.mode == modeConst } func (tv TCTypeAndValue) Addressable() bool { return tv.mode == modeVar } // Info holds the result of type-checking a set of Files. // Consumers access type info for each expression and identifier. type Info struct { // Types maps each expression to its type and value. // For type expressions, TCTypeAndValue.IsType() is true. // For constants, TCTypeAndValue.Value is non-nil. Types map[Expr]TCTypeAndValue // Defs maps each identifier that declares something to the object it declares. // nil objects represent anonymous declarations (blank _ idents). Defs map[*Name]Object // Uses maps each identifier that is used (not declared) to the object it denotes. Uses map[*Name]Object // Implicits maps nodes to the object they implicitly declare. // For imports: ImportDecl -> *PkgName // For type switches: the guarded var in each case clause Implicits map[Node]Object // Scopes maps AST nodes to the scope they open. // File -> file scope, FuncDecl/FuncLit -> function scope, etc. Scopes map[Node]*Scope // Selections maps selector expressions X.f to the selection. Selections map[*SelectorExpr]*Selection } // Selection describes a field or method selection X.f. type Selection struct { kind SelectionKind recv Type // type of X obj Object // selected field or method index []int // path of field indices (for embedded fields) indir bool // true if recv contains a pointer indirection } type SelectionKind int const ( FieldVal SelectionKind = iota MethodVal MethodExpr ) func (s *Selection) Kind() SelectionKind { return s.kind } func (s *Selection) Recv() Type { return s.recv } func (s *Selection) Obj() Object { return s.obj } func (s *Selection) Index() []int { return s.index } func (s *Selection) Indirect() bool { return s.indir } func (s *Selection) Type() Type { switch s.kind { case FieldVal: return s.obj.Type() case MethodVal: sig := s.obj.(*TCFunc).Signature() // bound method: drop the receiver parameter return NewSignature(nil, sig.params, sig.results, sig.variadic) case MethodExpr: // unbound: receiver becomes first parameter return s.obj.(*TCFunc).Signature() } return nil } func newInfo() *Info { return &Info{ Types: map[Expr]TCTypeAndValue{}, Defs: map[*Name]Object{}, Uses: map[*Name]Object{}, Implicits: map[Node]Object{}, Scopes: map[Node]*Scope{}, Selections: map[*SelectorExpr]*Selection{}, } } // TypeOf returns the type of expression e, or nil if unknown. func (info *Info) TypeOf(e Expr) Type { if tv, ok := info.Types[e]; ok { return tv.Type } return nil } // ObjectOf returns the object denoted by identifier id, or nil. func (info *Info) ObjectOf(id *Name) Object { if obj, ok := info.Defs[id]; ok { return obj } return info.Uses[id] }