]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgo/go/exp/types/staging/check.go
libgo: Update to current sources.
[thirdparty/gcc.git] / libgo / go / exp / types / staging / 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/token"
13 "sort"
14 )
15
16 type checker struct {
17 fset *token.FileSet
18 pkg *ast.Package
19 errh func(token.Pos, string)
20 mapf func(ast.Expr, Type)
21
22 // lazily initialized
23 firsterr error
24 filenames []string // sorted list of package file names for reproducible iteration order
25 initexprs map[*ast.ValueSpec][]ast.Expr // "inherited" initialization expressions for constant declarations
26 }
27
28 // declare declares an object of the given kind and name (ident) in scope;
29 // decl is the corresponding declaration in the AST. An error is reported
30 // if the object was declared before.
31 //
32 // TODO(gri) This is very similar to the declare function in go/parser; it
33 // is only used to associate methods with their respective receiver base types.
34 // In a future version, it might be simpler and cleaner do to all the resolution
35 // in the type-checking phase. It would simplify the parser, AST, and also
36 // reduce some amount of code duplication.
37 //
38 func (check *checker) declare(scope *ast.Scope, kind ast.ObjKind, ident *ast.Ident, decl ast.Decl) {
39 assert(ident.Obj == nil) // identifier already declared or resolved
40 obj := ast.NewObj(kind, ident.Name)
41 obj.Decl = decl
42 ident.Obj = obj
43 if ident.Name != "_" {
44 if alt := scope.Insert(obj); alt != nil {
45 prevDecl := ""
46 if pos := alt.Pos(); pos.IsValid() {
47 prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", check.fset.Position(pos))
48 }
49 check.errorf(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl))
50 }
51 }
52 }
53
54 func (check *checker) valueSpec(pos token.Pos, obj *ast.Object, lhs []*ast.Ident, typ ast.Expr, rhs []ast.Expr, iota int) {
55 if len(lhs) == 0 {
56 check.invalidAST(pos, "missing lhs in declaration")
57 return
58 }
59
60 var t Type
61 if typ != nil {
62 t = check.typ(typ, false)
63 }
64
65 // len(lhs) >= 1
66 if len(lhs) == len(rhs) {
67 // check only corresponding lhs and rhs
68 var l, r ast.Expr
69 for i, ident := range lhs {
70 if ident.Obj == obj {
71 l = lhs[i]
72 r = rhs[i]
73 break
74 }
75 }
76 assert(l != nil)
77 obj.Type = t
78 // check rhs
79 var x operand
80 check.expr(&x, r, t, iota)
81 // assign to lhs
82 check.assignment(l, &x, true)
83 return
84 }
85
86 if t != nil {
87 for _, name := range lhs {
88 name.Obj.Type = t
89 }
90 }
91
92 // check initial values, if any
93 if len(rhs) > 0 {
94 // TODO(gri) should try to avoid this conversion
95 lhx := make([]ast.Expr, len(lhs))
96 for i, e := range lhs {
97 lhx[i] = e
98 }
99 check.assignNtoM(lhx, rhs, true, iota)
100 }
101 }
102
103 // ident type checks an identifier.
104 func (check *checker) ident(name *ast.Ident, cycleOk bool) {
105 obj := name.Obj
106 if obj == nil {
107 check.invalidAST(name.Pos(), "missing object for %s", name.Name)
108 return
109 }
110
111 if obj.Type != nil {
112 // object has already been type checked
113 return
114 }
115
116 switch obj.Kind {
117 case ast.Bad, ast.Pkg:
118 // nothing to do
119
120 case ast.Con, ast.Var:
121 // The obj.Data field for constants and variables is initialized
122 // to the respective (hypothetical, for variables) iota value by
123 // the parser. The object's fields can be in one of the following
124 // states:
125 // Type != nil => the constant value is Data
126 // Type == nil => the object is not typechecked yet, and Data can be:
127 // Data is int => Data is the value of iota for this declaration
128 // Data == nil => the object's expression is being evaluated
129 if obj.Data == nil {
130 check.errorf(obj.Pos(), "illegal cycle in initialization of %s", obj.Name)
131 return
132 }
133 spec := obj.Decl.(*ast.ValueSpec)
134 iota := obj.Data.(int)
135 obj.Data = nil
136 // determine initialization expressions
137 values := spec.Values
138 if len(values) == 0 && obj.Kind == ast.Con {
139 values = check.initexprs[spec]
140 }
141 check.valueSpec(spec.Pos(), obj, spec.Names, spec.Type, values, iota)
142
143 case ast.Typ:
144 typ := &NamedType{Obj: obj}
145 obj.Type = typ // "mark" object so recursion terminates
146 typ.Underlying = underlying(check.typ(obj.Decl.(*ast.TypeSpec).Type, cycleOk))
147 // collect associated methods, if any
148 if obj.Data != nil {
149 scope := obj.Data.(*ast.Scope)
150 // struct fields must not conflict with methods
151 if t, ok := typ.Underlying.(*Struct); ok {
152 for _, f := range t.Fields {
153 if m := scope.Lookup(f.Name); m != nil {
154 check.errorf(m.Pos(), "type %s has both field and method named %s", obj.Name, f.Name)
155 }
156 }
157 }
158 // collect methods
159 methods := make(ObjList, len(scope.Objects))
160 i := 0
161 for _, m := range scope.Objects {
162 methods[i] = m
163 i++
164 }
165 methods.Sort()
166 typ.Methods = methods
167 // methods cannot be associated with an interface type
168 // (do this check after sorting for reproducible error positions - needed for testing)
169 if _, ok := typ.Underlying.(*Interface); ok {
170 for _, m := range methods {
171 recv := m.Decl.(*ast.FuncDecl).Recv.List[0].Type
172 check.errorf(recv.Pos(), "invalid receiver type %s (%s is an interface type)", obj.Name, obj.Name)
173 }
174 }
175 }
176
177 case ast.Fun:
178 fdecl := obj.Decl.(*ast.FuncDecl)
179 ftyp := check.typ(fdecl.Type, cycleOk).(*Signature)
180 obj.Type = ftyp
181 if fdecl.Recv != nil {
182 // TODO(gri) handle method receiver
183 }
184 check.stmt(fdecl.Body)
185
186 default:
187 panic("unreachable")
188 }
189 }
190
191 // assocInitvals associates "inherited" initialization expressions
192 // with the corresponding *ast.ValueSpec in the check.initexprs map
193 // for constant declarations without explicit initialization expressions.
194 //
195 func (check *checker) assocInitvals(decl *ast.GenDecl) {
196 var values []ast.Expr
197 for _, s := range decl.Specs {
198 if s, ok := s.(*ast.ValueSpec); ok {
199 if len(s.Values) > 0 {
200 values = s.Values
201 } else {
202 check.initexprs[s] = values
203 }
204 }
205 }
206 if len(values) == 0 {
207 check.invalidAST(decl.Pos(), "no initialization values provided")
208 }
209 }
210
211 // assocMethod associates a method declaration with the respective
212 // receiver base type. meth.Recv must exist.
213 //
214 func (check *checker) assocMethod(meth *ast.FuncDecl) {
215 // The receiver type is one of the following (enforced by parser):
216 // - *ast.Ident
217 // - *ast.StarExpr{*ast.Ident}
218 // - *ast.BadExpr (parser error)
219 typ := meth.Recv.List[0].Type
220 if ptr, ok := typ.(*ast.StarExpr); ok {
221 typ = ptr.X
222 }
223 // determine receiver base type object (or nil if error)
224 var obj *ast.Object
225 if ident, ok := typ.(*ast.Ident); ok && ident.Obj != nil {
226 obj = ident.Obj
227 if obj.Kind != ast.Typ {
228 check.errorf(ident.Pos(), "%s is not a type", ident.Name)
229 obj = nil
230 }
231 // TODO(gri) determine if obj was defined in this package
232 /*
233 if check.notLocal(obj) {
234 check.errorf(ident.Pos(), "cannot define methods on non-local type %s", ident.Name)
235 obj = nil
236 }
237 */
238 } else {
239 // If it's not an identifier or the identifier wasn't declared/resolved,
240 // the parser/resolver already reported an error. Nothing to do here.
241 }
242 // determine base type scope (or nil if error)
243 var scope *ast.Scope
244 if obj != nil {
245 if obj.Data != nil {
246 scope = obj.Data.(*ast.Scope)
247 } else {
248 scope = ast.NewScope(nil)
249 obj.Data = scope
250 }
251 } else {
252 // use a dummy scope so that meth can be declared in
253 // presence of an error and get an associated object
254 // (always use a new scope so that we don't get double
255 // declaration errors)
256 scope = ast.NewScope(nil)
257 }
258 check.declare(scope, ast.Fun, meth.Name, meth)
259 }
260
261 func (check *checker) assocInitvalsOrMethod(decl ast.Decl) {
262 switch d := decl.(type) {
263 case *ast.GenDecl:
264 if d.Tok == token.CONST {
265 check.assocInitvals(d)
266 }
267 case *ast.FuncDecl:
268 if d.Recv != nil {
269 check.assocMethod(d)
270 }
271 }
272 }
273
274 func (check *checker) decl(decl ast.Decl) {
275 switch d := decl.(type) {
276 case *ast.BadDecl:
277 // ignore
278 case *ast.GenDecl:
279 for _, spec := range d.Specs {
280 switch s := spec.(type) {
281 case *ast.ImportSpec:
282 // nothing to do (handled by ast.NewPackage)
283 case *ast.ValueSpec:
284 for _, name := range s.Names {
285 if name.Name == "_" {
286 // TODO(gri) why is _ special here?
287 } else {
288 check.ident(name, false)
289 }
290 }
291 case *ast.TypeSpec:
292 check.ident(s.Name, false)
293 default:
294 check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s)
295 }
296 }
297 case *ast.FuncDecl:
298 check.ident(d.Name, false)
299 default:
300 check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
301 }
302 }
303
304 // iterate calls f for each package-level declaration.
305 func (check *checker) iterate(f func(*checker, ast.Decl)) {
306 list := check.filenames
307
308 if list == nil {
309 // initialize lazily
310 for filename := range check.pkg.Files {
311 list = append(list, filename)
312 }
313 sort.Strings(list)
314 check.filenames = list
315 }
316
317 for _, filename := range list {
318 for _, decl := range check.pkg.Files[filename].Decls {
319 f(check, decl)
320 }
321 }
322 }
323
324 // A bailout panic is raised to indicate early termination.
325 type bailout struct{}
326
327 func check(fset *token.FileSet, pkg *ast.Package, errh func(token.Pos, string), f func(ast.Expr, Type)) (err error) {
328 // initialize checker
329 var check checker
330 check.fset = fset
331 check.pkg = pkg
332 check.errh = errh
333 check.mapf = f
334 check.initexprs = make(map[*ast.ValueSpec][]ast.Expr)
335
336 // handle bailouts
337 defer func() {
338 if p := recover(); p != nil {
339 _ = p.(bailout) // re-panic if not a bailout
340 }
341 err = check.firsterr
342 }()
343
344 // determine missing constant initialization expressions
345 // and associate methods with types
346 check.iterate((*checker).assocInitvalsOrMethod)
347
348 // typecheck all declarations
349 check.iterate((*checker).decl)
350
351 return
352 }