Imported Upstream version 4.7.2
[platform/upstream/gcc48.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         "strconv"
15 )
16
17 const debug = false
18
19 type checker struct {
20         fset   *token.FileSet
21         errors scanner.ErrorList
22         types  map[ast.Expr]Type
23 }
24
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)
28         return msg
29 }
30
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) {
34         if list != nil {
35                 for _, field := range list.List {
36                         ftype := field.Type
37                         if t, ok := ftype.(*ast.Ellipsis); ok {
38                                 ftype = t.Elt
39                                 isVariadic = true
40                         }
41                         typ := c.makeType(ftype, cycleOk)
42                         tag := ""
43                         if field.Tag != nil {
44                                 assert(field.Tag.Kind == token.STRING)
45                                 tag, _ = strconv.Unquote(field.Tag.Value)
46                         }
47                         if len(field.Names) > 0 {
48                                 // named fields
49                                 for _, name := range field.Names {
50                                         obj := name.Obj
51                                         obj.Type = typ
52                                         fields = append(fields, obj)
53                                         if tok == token.STRUCT {
54                                                 tags = append(tags, tag)
55                                         }
56                                 }
57                         } else {
58                                 // anonymous field
59                                 switch tok {
60                                 case token.STRUCT:
61                                         tags = append(tags, tag)
62                                         fallthrough
63                                 case token.FUNC:
64                                         obj := ast.NewObj(ast.Var, "")
65                                         obj.Type = typ
66                                         fields = append(fields, obj)
67                                 case token.INTERFACE:
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")
75                                         }
76                                 default:
77                                         panic("unreachable")
78                                 }
79                         }
80                 }
81         }
82         return
83 }
84
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.
88 //
89 func (c *checker) makeType(x ast.Expr, cycleOk bool) (typ Type) {
90         if debug {
91                 fmt.Printf("makeType (cycleOk = %v)\n", cycleOk)
92                 ast.Print(c.fset, x)
93                 defer func() {
94                         fmt.Printf("-> %T %v\n\n", typ, typ)
95                 }()
96         }
97
98         switch t := x.(type) {
99         case *ast.BadExpr:
100                 return &Bad{}
101
102         case *ast.Ident:
103                 // type name
104                 obj := t.Obj
105                 if obj == nil {
106                         // unresolved identifier (error has been reported before)
107                         return &Bad{Msg: "unresolved identifier"}
108                 }
109                 if obj.Kind != ast.Typ {
110                         msg := c.errorf(t.Pos(), "%s is not a type", t.Name)
111                         return &Bad{Msg: msg}
112                 }
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}
120                 }
121                 return obj.Type.(Type)
122
123         case *ast.ParenExpr:
124                 return c.makeType(t.X, cycleOk)
125
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}
135                                 }
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
140                         }
141                 }
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}
145
146         case *ast.StarExpr:
147                 return &Pointer{Base: c.makeType(t.X, true)}
148
149         case *ast.ArrayType:
150                 if t.Len != nil {
151                         // TODO(gri) compute length
152                         return &Array{Elt: c.makeType(t.Elt, cycleOk)}
153                 }
154                 return &Slice{Elt: c.makeType(t.Elt, true)}
155
156         case *ast.StructType:
157                 fields, tags, _ := c.collectFields(token.STRUCT, t.Fields, cycleOk)
158                 return &Struct{Fields: fields, Tags: tags}
159
160         case *ast.FuncType:
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}
164
165         case *ast.InterfaceType:
166                 methods, _, _ := c.collectFields(token.INTERFACE, t.Methods, cycleOk)
167                 methods.Sort()
168                 return &Interface{Methods: methods}
169
170         case *ast.MapType:
171                 return &Map{Key: c.makeType(t.Key, true), Elt: c.makeType(t.Key, true)}
172
173         case *ast.ChanType:
174                 return &Chan{Dir: t.Dir, Elt: c.makeType(t.Value, true)}
175         }
176
177         panic(fmt.Sprintf("unreachable (%T)", x))
178 }
179
180 // checkObj type checks an object.
181 func (c *checker) checkObj(obj *ast.Object, ref bool) {
182         if obj.Type != nil {
183                 // object has already been type checked
184                 return
185         }
186
187         switch obj.Kind {
188         case ast.Bad:
189                 // ignore
190
191         case ast.Con:
192                 // TODO(gri) complete this
193
194         case ast.Typ:
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))
198
199         case ast.Var:
200                 // TODO(gri) complete this
201
202         case ast.Fun:
203                 // TODO(gri) complete this
204
205         default:
206                 panic("unreachable")
207         }
208 }
209
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
213 // there are errors.
214 //
215 func Check(fset *token.FileSet, pkg *ast.Package) (types map[ast.Expr]Type, err error) {
216         var c checker
217         c.fset = fset
218         c.types = make(map[ast.Expr]Type)
219
220         for _, obj := range pkg.Scope.Objects {
221                 c.checkObj(obj, false)
222         }
223
224         c.errors.RemoveMultiples()
225         return c.types, c.errors.Err()
226 }