1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // This file implements the Check function, which typechecks a package.
21 errors scanner.ErrorList
22 types map[ast.Expr]Type
25 func (c *checker) errorf(pos token.Pos, format string, args ...interface{}) string {
26 msg := fmt.Sprintf(format, args...)
27 c.errors.Add(c.fset.Position(pos), msg)
31 // collectFields collects struct fields tok = token.STRUCT), interface methods
32 // (tok = token.INTERFACE), and function arguments/results (tok = token.FUNC).
33 func (c *checker) collectFields(tok token.Token, list *ast.FieldList, cycleOk bool) (fields ObjList, tags []string, isVariadic bool) {
35 for _, field := range list.List {
37 if t, ok := ftype.(*ast.Ellipsis); ok {
41 typ := c.makeType(ftype, cycleOk)
44 assert(field.Tag.Kind == token.STRING)
45 tag, _ = strconv.Unquote(field.Tag.Value)
47 if len(field.Names) > 0 {
49 for _, name := range field.Names {
52 fields = append(fields, obj)
53 if tok == token.STRUCT {
54 tags = append(tags, tag)
61 tags = append(tags, tag)
64 obj := ast.NewObj(ast.Var, "")
66 fields = append(fields, obj)
68 utyp := Underlying(typ)
69 if typ, ok := utyp.(*Interface); ok {
70 // TODO(gri) This is not good enough. Check for double declarations!
71 fields = append(fields, typ.Methods...)
72 } else if _, ok := utyp.(*Bad); !ok {
73 // if utyp is Bad, don't complain (the root cause was reported before)
74 c.errorf(ftype.Pos(), "interface contains embedded non-interface type")
85 // makeType makes a new type for an AST type specification x or returns
86 // the type referred to by a type name x. If cycleOk is set, a type may
87 // refer to itself directly or indirectly; otherwise cycles are errors.
89 func (c *checker) makeType(x ast.Expr, cycleOk bool) (typ Type) {
91 fmt.Printf("makeType (cycleOk = %v)\n", cycleOk)
94 fmt.Printf("-> %T %v\n\n", typ, typ)
98 switch t := x.(type) {
106 // unresolved identifier (error has been reported before)
107 return &Bad{Msg: "unresolved identifier"}
109 if obj.Kind != ast.Typ {
110 msg := c.errorf(t.Pos(), "%s is not a type", t.Name)
111 return &Bad{Msg: msg}
113 c.checkObj(obj, cycleOk)
114 if !cycleOk && obj.Type.(*Name).Underlying == nil {
115 // TODO(gri) Enable this message again once its position
116 // is independent of the underlying map implementation.
117 // msg := c.errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name)
118 msg := "illegal cycle"
119 return &Bad{Msg: msg}
121 return obj.Type.(Type)
124 return c.makeType(t.X, cycleOk)
126 case *ast.SelectorExpr:
127 // qualified identifier
128 // TODO (gri) eventually, this code belongs to expression
129 // type checking - here for the time being
130 if ident, ok := t.X.(*ast.Ident); ok {
131 if obj := ident.Obj; obj != nil {
132 if obj.Kind != ast.Pkg {
133 msg := c.errorf(ident.Pos(), "%s is not a package", obj.Name)
134 return &Bad{Msg: msg}
136 // TODO(gri) we have a package name but don't
137 // have the mapping from package name to package
138 // scope anymore (created in ast.NewPackage).
139 return &Bad{} // for now
142 // TODO(gri) can this really happen (the parser should have excluded this)?
143 msg := c.errorf(t.Pos(), "expected qualified identifier")
144 return &Bad{Msg: msg}
147 return &Pointer{Base: c.makeType(t.X, true)}
151 // TODO(gri) compute length
152 return &Array{Elt: c.makeType(t.Elt, cycleOk)}
154 return &Slice{Elt: c.makeType(t.Elt, true)}
156 case *ast.StructType:
157 fields, tags, _ := c.collectFields(token.STRUCT, t.Fields, cycleOk)
158 return &Struct{Fields: fields, Tags: tags}
161 params, _, _ := c.collectFields(token.FUNC, t.Params, true)
162 results, _, isVariadic := c.collectFields(token.FUNC, t.Results, true)
163 return &Func{Recv: nil, Params: params, Results: results, IsVariadic: isVariadic}
165 case *ast.InterfaceType:
166 methods, _, _ := c.collectFields(token.INTERFACE, t.Methods, cycleOk)
168 return &Interface{Methods: methods}
171 return &Map{Key: c.makeType(t.Key, true), Elt: c.makeType(t.Key, true)}
174 return &Chan{Dir: t.Dir, Elt: c.makeType(t.Value, true)}
177 panic(fmt.Sprintf("unreachable (%T)", x))
180 // checkObj type checks an object.
181 func (c *checker) checkObj(obj *ast.Object, ref bool) {
183 // object has already been type checked
192 // TODO(gri) complete this
195 typ := &Name{Obj: obj}
196 obj.Type = typ // "mark" object so recursion terminates
197 typ.Underlying = Underlying(c.makeType(obj.Decl.(*ast.TypeSpec).Type, ref))
200 // TODO(gri) complete this
203 // TODO(gri) complete this
210 // Check typechecks a package.
211 // It augments the AST by assigning types to all ast.Objects and returns a map
212 // of types for all expression nodes in statements, and a scanner.ErrorList if
215 func Check(fset *token.FileSet, pkg *ast.Package) (types map[ast.Expr]Type, err error) {
218 c.types = make(map[ast.Expr]Type)
220 for _, obj := range pkg.Scope.Objects {
221 c.checkObj(obj, false)
224 c.errors.RemoveMultiples()
225 return c.types, c.errors.Err()