OSDN Git Service

Update Go library to last weekly.
[pf3gnuchains/gcc-fork.git] / libgo / go / exp / types / check.go
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.
4
5 // This file implements the Check function, which typechecks a package.
6
7 package types
8
9 import (
10         "fmt"
11         "go/ast"
12         "go/scanner"
13         "go/token"
14         "os"
15         "strconv"
16 )
17
18 const debug = false
19
20 type checker struct {
21         fset *token.FileSet
22         scanner.ErrorVector
23         types map[ast.Expr]Type
24 }
25
26 func (c *checker) errorf(pos token.Pos, format string, args ...interface{}) string {
27         msg := fmt.Sprintf(format, args...)
28         c.Error(c.fset.Position(pos), msg)
29         return msg
30 }
31
32 // collectFields collects struct fields tok = token.STRUCT), interface methods
33 // (tok = token.INTERFACE), and function arguments/results (tok = token.FUNC).
34 func (c *checker) collectFields(tok token.Token, list *ast.FieldList, cycleOk bool) (fields ObjList, tags []string, isVariadic bool) {
35         if list != nil {
36                 for _, field := range list.List {
37                         ftype := field.Type
38                         if t, ok := ftype.(*ast.Ellipsis); ok {
39                                 ftype = t.Elt
40                                 isVariadic = true
41                         }
42                         typ := c.makeType(ftype, cycleOk)
43                         tag := ""
44                         if field.Tag != nil {
45                                 assert(field.Tag.Kind == token.STRING)
46                                 tag, _ = strconv.Unquote(field.Tag.Value)
47                         }
48                         if len(field.Names) > 0 {
49                                 // named fields
50                                 for _, name := range field.Names {
51                                         obj := name.Obj
52                                         obj.Type = typ
53                                         fields = append(fields, obj)
54                                         if tok == token.STRUCT {
55                                                 tags = append(tags, tag)
56                                         }
57                                 }
58                         } else {
59                                 // anonymous field
60                                 switch tok {
61                                 case token.STRUCT:
62                                         tags = append(tags, tag)
63                                         fallthrough
64                                 case token.FUNC:
65                                         obj := ast.NewObj(ast.Var, "")
66                                         obj.Type = typ
67                                         fields = append(fields, obj)
68                                 case token.INTERFACE:
69                                         utyp := Underlying(typ)
70                                         if typ, ok := utyp.(*Interface); ok {
71                                                 // TODO(gri) This is not good enough. Check for double declarations!
72                                                 fields = append(fields, typ.Methods...)
73                                         } else if _, ok := utyp.(*Bad); !ok {
74                                                 // if utyp is Bad, don't complain (the root cause was reported before)
75                                                 c.errorf(ftype.Pos(), "interface contains embedded non-interface type")
76                                         }
77                                 default:
78                                         panic("unreachable")
79                                 }
80                         }
81                 }
82         }
83         return
84 }
85
86 // makeType makes a new type for an AST type specification x or returns
87 // the type referred to by a type name x. If cycleOk is set, a type may
88 // refer to itself directly or indirectly; otherwise cycles are errors.
89 //
90 func (c *checker) makeType(x ast.Expr, cycleOk bool) (typ Type) {
91         if debug {
92                 fmt.Printf("makeType (cycleOk = %v)\n", cycleOk)
93                 ast.Print(c.fset, x)
94                 defer func() {
95                         fmt.Printf("-> %T %v\n\n", typ, typ)
96                 }()
97         }
98
99         switch t := x.(type) {
100         case *ast.BadExpr:
101                 return &Bad{}
102
103         case *ast.Ident:
104                 // type name
105                 obj := t.Obj
106                 if obj == nil {
107                         // unresolved identifier (error has been reported before)
108                         return &Bad{Msg: "unresolved identifier"}
109                 }
110                 if obj.Kind != ast.Typ {
111                         msg := c.errorf(t.Pos(), "%s is not a type", t.Name)
112                         return &Bad{Msg: msg}
113                 }
114                 c.checkObj(obj, cycleOk)
115                 if !cycleOk && obj.Type.(*Name).Underlying == nil {
116                         // TODO(gri) Enable this message again once its position
117                         // is independent of the underlying map implementation.
118                         // msg := c.errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name)
119                         msg := "illegal cycle"
120                         return &Bad{Msg: msg}
121                 }
122                 return obj.Type.(Type)
123
124         case *ast.ParenExpr:
125                 return c.makeType(t.X, cycleOk)
126
127         case *ast.SelectorExpr:
128                 // qualified identifier
129                 // TODO (gri) eventually, this code belongs to expression
130                 //            type checking - here for the time being
131                 if ident, ok := t.X.(*ast.Ident); ok {
132                         if obj := ident.Obj; obj != nil {
133                                 if obj.Kind != ast.Pkg {
134                                         msg := c.errorf(ident.Pos(), "%s is not a package", obj.Name)
135                                         return &Bad{Msg: msg}
136                                 }
137                                 // TODO(gri) we have a package name but don't
138                                 // have the mapping from package name to package
139                                 // scope anymore (created in ast.NewPackage).
140                                 return &Bad{} // for now
141                         }
142                 }
143                 // TODO(gri) can this really happen (the parser should have excluded this)?
144                 msg := c.errorf(t.Pos(), "expected qualified identifier")
145                 return &Bad{Msg: msg}
146
147         case *ast.StarExpr:
148                 return &Pointer{Base: c.makeType(t.X, true)}
149
150         case *ast.ArrayType:
151                 if t.Len != nil {
152                         // TODO(gri) compute length
153                         return &Array{Elt: c.makeType(t.Elt, cycleOk)}
154                 }
155                 return &Slice{Elt: c.makeType(t.Elt, true)}
156
157         case *ast.StructType:
158                 fields, tags, _ := c.collectFields(token.STRUCT, t.Fields, cycleOk)
159                 return &Struct{Fields: fields, Tags: tags}
160
161         case *ast.FuncType:
162                 params, _, _ := c.collectFields(token.FUNC, t.Params, true)
163                 results, _, isVariadic := c.collectFields(token.FUNC, t.Results, true)
164                 return &Func{Recv: nil, Params: params, Results: results, IsVariadic: isVariadic}
165
166         case *ast.InterfaceType:
167                 methods, _, _ := c.collectFields(token.INTERFACE, t.Methods, cycleOk)
168                 methods.Sort()
169                 return &Interface{Methods: methods}
170
171         case *ast.MapType:
172                 return &Map{Key: c.makeType(t.Key, true), Elt: c.makeType(t.Key, true)}
173
174         case *ast.ChanType:
175                 return &Chan{Dir: t.Dir, Elt: c.makeType(t.Value, true)}
176         }
177
178         panic(fmt.Sprintf("unreachable (%T)", x))
179 }
180
181 // checkObj type checks an object.
182 func (c *checker) checkObj(obj *ast.Object, ref bool) {
183         if obj.Type != nil {
184                 // object has already been type checked
185                 return
186         }
187
188         switch obj.Kind {
189         case ast.Bad:
190                 // ignore
191
192         case ast.Con:
193                 // TODO(gri) complete this
194
195         case ast.Typ:
196                 typ := &Name{Obj: obj}
197                 obj.Type = typ // "mark" object so recursion terminates
198                 typ.Underlying = Underlying(c.makeType(obj.Decl.(*ast.TypeSpec).Type, ref))
199
200         case ast.Var:
201                 // TODO(gri) complete this
202
203         case ast.Fun:
204                 // TODO(gri) complete this
205
206         default:
207                 panic("unreachable")
208         }
209 }
210
211 // Check typechecks a package.
212 // It augments the AST by assigning types to all ast.Objects and returns a map
213 // of types for all expression nodes in statements, and a scanner.ErrorList if
214 // there are errors.
215 //
216 func Check(fset *token.FileSet, pkg *ast.Package) (types map[ast.Expr]Type, err os.Error) {
217         var c checker
218         c.fset = fset
219         c.types = make(map[ast.Expr]Type)
220
221         for _, obj := range pkg.Scope.Objects {
222                 c.checkObj(obj, false)
223         }
224
225         return c.types, c.GetError(scanner.NoMultiples)
226 }