]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/typecheck/dcl.go
[dev.typeparams] cmd/compile: refactor irgen's handling of ":="
[gostls13.git] / src / cmd / compile / internal / typecheck / dcl.go
1 // Copyright 2009 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 package typecheck
6
7 import (
8         "fmt"
9         "strconv"
10
11         "cmd/compile/internal/base"
12         "cmd/compile/internal/ir"
13         "cmd/compile/internal/types"
14         "cmd/internal/src"
15 )
16
17 var DeclContext ir.Class = ir.PEXTERN // PEXTERN/PAUTO
18
19 func DeclFunc(sym *types.Sym, tfn ir.Ntype) *ir.Func {
20         if tfn.Op() != ir.OTFUNC {
21                 base.Fatalf("expected OTFUNC node, got %v", tfn)
22         }
23
24         fn := ir.NewFunc(base.Pos)
25         fn.Nname = ir.NewNameAt(base.Pos, sym)
26         fn.Nname.Func = fn
27         fn.Nname.Defn = fn
28         fn.Nname.Ntype = tfn
29         ir.MarkFunc(fn.Nname)
30         StartFuncBody(fn)
31         fn.Nname.Ntype = typecheckNtype(fn.Nname.Ntype)
32         return fn
33 }
34
35 // Declare records that Node n declares symbol n.Sym in the specified
36 // declaration context.
37 func Declare(n *ir.Name, ctxt ir.Class) {
38         if ir.IsBlank(n) {
39                 return
40         }
41
42         s := n.Sym()
43
44         // kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
45         if !inimport && !TypecheckAllowed && s.Pkg != types.LocalPkg {
46                 base.ErrorfAt(n.Pos(), "cannot declare name %v", s)
47         }
48
49         if ctxt == ir.PEXTERN {
50                 if s.Name == "init" {
51                         base.ErrorfAt(n.Pos(), "cannot declare init - must be func")
52                 }
53                 if s.Name == "main" && s.Pkg.Name == "main" {
54                         base.ErrorfAt(n.Pos(), "cannot declare main - must be func")
55                 }
56                 Target.Externs = append(Target.Externs, n)
57         } else {
58                 if ir.CurFunc == nil && ctxt == ir.PAUTO {
59                         base.Pos = n.Pos()
60                         base.Fatalf("automatic outside function")
61                 }
62                 if ir.CurFunc != nil && ctxt != ir.PFUNC && n.Op() == ir.ONAME {
63                         ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
64                 }
65                 types.Pushdcl(s)
66                 n.Curfn = ir.CurFunc
67         }
68
69         if ctxt == ir.PAUTO {
70                 n.SetFrameOffset(0)
71         }
72
73         if s.Block == types.Block {
74                 // functype will print errors about duplicate function arguments.
75                 // Don't repeat the error here.
76                 if ctxt != ir.PPARAM && ctxt != ir.PPARAMOUT {
77                         Redeclared(n.Pos(), s, "in this block")
78                 }
79         }
80
81         s.Block = types.Block
82         s.Lastlineno = base.Pos
83         s.Def = n
84         n.Class = ctxt
85         if ctxt == ir.PFUNC {
86                 n.Sym().SetFunc(true)
87         }
88
89         autoexport(n, ctxt)
90 }
91
92 // Export marks n for export (or reexport).
93 func Export(n *ir.Name) {
94         if n.Sym().OnExportList() {
95                 return
96         }
97         n.Sym().SetOnExportList(true)
98
99         if base.Flag.E != 0 {
100                 fmt.Printf("export symbol %v\n", n.Sym())
101         }
102
103         Target.Exports = append(Target.Exports, n)
104 }
105
106 // Redeclared emits a diagnostic about symbol s being redeclared at pos.
107 func Redeclared(pos src.XPos, s *types.Sym, where string) {
108         if !s.Lastlineno.IsKnown() {
109                 pkgName := DotImportRefs[s.Def.(*ir.Ident)]
110                 base.ErrorfAt(pos, "%v redeclared %s\n"+
111                         "\t%v: previous declaration during import %q", s, where, base.FmtPos(pkgName.Pos()), pkgName.Pkg.Path)
112         } else {
113                 prevPos := s.Lastlineno
114
115                 // When an import and a declaration collide in separate files,
116                 // present the import as the "redeclared", because the declaration
117                 // is visible where the import is, but not vice versa.
118                 // See issue 4510.
119                 if s.Def == nil {
120                         pos, prevPos = prevPos, pos
121                 }
122
123                 base.ErrorfAt(pos, "%v redeclared %s\n"+
124                         "\t%v: previous declaration", s, where, base.FmtPos(prevPos))
125         }
126 }
127
128 // declare the function proper
129 // and declare the arguments.
130 // called in extern-declaration context
131 // returns in auto-declaration context.
132 func StartFuncBody(fn *ir.Func) {
133         // change the declaration context from extern to auto
134         funcStack = append(funcStack, funcStackEnt{ir.CurFunc, DeclContext})
135         ir.CurFunc = fn
136         DeclContext = ir.PAUTO
137
138         types.Markdcl()
139
140         if fn.Nname.Ntype != nil {
141                 funcargs(fn.Nname.Ntype.(*ir.FuncType))
142         } else {
143                 funcargs2(fn.Type())
144         }
145 }
146
147 // finish the body.
148 // called in auto-declaration context.
149 // returns in extern-declaration context.
150 func FinishFuncBody() {
151         // change the declaration context from auto to previous context
152         types.Popdcl()
153         var e funcStackEnt
154         funcStack, e = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1]
155         ir.CurFunc, DeclContext = e.curfn, e.dclcontext
156 }
157
158 func CheckFuncStack() {
159         if len(funcStack) != 0 {
160                 base.Fatalf("funcStack is non-empty: %v", len(funcStack))
161         }
162 }
163
164 // Add a method, declared as a function.
165 // - msym is the method symbol
166 // - t is function type (with receiver)
167 // Returns a pointer to the existing or added Field; or nil if there's an error.
168 func addmethod(n *ir.Func, msym *types.Sym, t *types.Type, local, nointerface bool) *types.Field {
169         if msym == nil {
170                 base.Fatalf("no method symbol")
171         }
172
173         // get parent type sym
174         rf := t.Recv() // ptr to this structure
175         if rf == nil {
176                 base.Errorf("missing receiver")
177                 return nil
178         }
179
180         mt := types.ReceiverBaseType(rf.Type)
181         if mt == nil || mt.Sym() == nil {
182                 pa := rf.Type
183                 t := pa
184                 if t != nil && t.IsPtr() {
185                         if t.Sym() != nil {
186                                 base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t)
187                                 return nil
188                         }
189                         t = t.Elem()
190                 }
191
192                 switch {
193                 case t == nil || t.Broke():
194                         // rely on typecheck having complained before
195                 case t.Sym() == nil:
196                         base.Errorf("invalid receiver type %v (%v is not a defined type)", pa, t)
197                 case t.IsPtr():
198                         base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t)
199                 case t.IsInterface():
200                         base.Errorf("invalid receiver type %v (%v is an interface type)", pa, t)
201                 default:
202                         // Should have picked off all the reasons above,
203                         // but just in case, fall back to generic error.
204                         base.Errorf("invalid receiver type %v (%L / %L)", pa, pa, t)
205                 }
206                 return nil
207         }
208
209         if local && mt.Sym().Pkg != types.LocalPkg {
210                 base.Errorf("cannot define new methods on non-local type %v", mt)
211                 return nil
212         }
213
214         if msym.IsBlank() {
215                 return nil
216         }
217
218         if mt.IsStruct() {
219                 for _, f := range mt.Fields().Slice() {
220                         if f.Sym == msym {
221                                 base.Errorf("type %v has both field and method named %v", mt, msym)
222                                 f.SetBroke(true)
223                                 return nil
224                         }
225                 }
226         }
227
228         for _, f := range mt.Methods().Slice() {
229                 if msym.Name != f.Sym.Name {
230                         continue
231                 }
232                 // types.Identical only checks that incoming and result parameters match,
233                 // so explicitly check that the receiver parameters match too.
234                 if !types.Identical(t, f.Type) || !types.Identical(t.Recv().Type, f.Type.Recv().Type) {
235                         base.Errorf("method redeclared: %v.%v\n\t%v\n\t%v", mt, msym, f.Type, t)
236                 }
237                 return f
238         }
239
240         f := types.NewField(base.Pos, msym, t)
241         f.Nname = n.Nname
242         f.SetNointerface(nointerface)
243
244         mt.Methods().Append(f)
245         return f
246 }
247
248 func autoexport(n *ir.Name, ctxt ir.Class) {
249         if n.Sym().Pkg != types.LocalPkg {
250                 return
251         }
252         if (ctxt != ir.PEXTERN && ctxt != ir.PFUNC) || DeclContext != ir.PEXTERN {
253                 return
254         }
255         if n.Type() != nil && n.Type().IsKind(types.TFUNC) && ir.IsMethod(n) {
256                 return
257         }
258
259         if types.IsExported(n.Sym().Name) || n.Sym().Name == "init" {
260                 Export(n)
261         }
262         if base.Flag.AsmHdr != "" && !n.Sym().Asm() {
263                 n.Sym().SetAsm(true)
264                 Target.Asms = append(Target.Asms, n)
265         }
266 }
267
268 // checkdupfields emits errors for duplicately named fields or methods in
269 // a list of struct or interface types.
270 func checkdupfields(what string, fss ...[]*types.Field) {
271         seen := make(map[*types.Sym]bool)
272         for _, fs := range fss {
273                 for _, f := range fs {
274                         if f.Sym == nil || f.Sym.IsBlank() {
275                                 continue
276                         }
277                         if seen[f.Sym] {
278                                 base.ErrorfAt(f.Pos, "duplicate %s %s", what, f.Sym.Name)
279                                 continue
280                         }
281                         seen[f.Sym] = true
282                 }
283         }
284 }
285
286 // structs, functions, and methods.
287 // they don't belong here, but where do they belong?
288 func checkembeddedtype(t *types.Type) {
289         if t == nil {
290                 return
291         }
292
293         if t.Sym() == nil && t.IsPtr() {
294                 t = t.Elem()
295                 if t.IsInterface() {
296                         base.Errorf("embedded type cannot be a pointer to interface")
297                 }
298         }
299
300         if t.IsPtr() || t.IsUnsafePtr() {
301                 base.Errorf("embedded type cannot be a pointer")
302         } else if t.Kind() == types.TFORW && !t.ForwardType().Embedlineno.IsKnown() {
303                 t.ForwardType().Embedlineno = base.Pos
304         }
305 }
306
307 // TODO(mdempsky): Move to package types.
308 func FakeRecv() *types.Field {
309         return types.NewField(src.NoXPos, nil, types.FakeRecvType())
310 }
311
312 var fakeRecvField = FakeRecv
313
314 var funcStack []funcStackEnt // stack of previous values of Curfn/dclcontext
315
316 type funcStackEnt struct {
317         curfn      *ir.Func
318         dclcontext ir.Class
319 }
320
321 func funcarg(n *ir.Field, ctxt ir.Class) {
322         if n.Sym == nil {
323                 return
324         }
325
326         name := ir.NewNameAt(n.Pos, n.Sym)
327         n.Decl = name
328         name.Ntype = n.Ntype
329         Declare(name, ctxt)
330 }
331
332 func funcarg2(f *types.Field, ctxt ir.Class) {
333         if f.Sym == nil {
334                 return
335         }
336         n := ir.NewNameAt(f.Pos, f.Sym)
337         f.Nname = n
338         n.SetType(f.Type)
339         Declare(n, ctxt)
340 }
341
342 func funcargs(nt *ir.FuncType) {
343         if nt.Op() != ir.OTFUNC {
344                 base.Fatalf("funcargs %v", nt.Op())
345         }
346
347         // declare the receiver and in arguments.
348         if nt.Recv != nil {
349                 funcarg(nt.Recv, ir.PPARAM)
350         }
351         for _, n := range nt.Params {
352                 funcarg(n, ir.PPARAM)
353         }
354
355         // declare the out arguments.
356         gen := len(nt.Params)
357         for _, n := range nt.Results {
358                 if n.Sym == nil {
359                         // Name so that escape analysis can track it. ~r stands for 'result'.
360                         n.Sym = LookupNum("~r", gen)
361                         gen++
362                 }
363                 if n.Sym.IsBlank() {
364                         // Give it a name so we can assign to it during return. ~b stands for 'blank'.
365                         // The name must be different from ~r above because if you have
366                         //      func f() (_ int)
367                         //      func g() int
368                         // f is allowed to use a plain 'return' with no arguments, while g is not.
369                         // So the two cases must be distinguished.
370                         n.Sym = LookupNum("~b", gen)
371                         gen++
372                 }
373
374                 funcarg(n, ir.PPARAMOUT)
375         }
376 }
377
378 // Same as funcargs, except run over an already constructed TFUNC.
379 // This happens during import, where the hidden_fndcl rule has
380 // used functype directly to parse the function's type.
381 func funcargs2(t *types.Type) {
382         if t.Kind() != types.TFUNC {
383                 base.Fatalf("funcargs2 %v", t)
384         }
385
386         for _, f := range t.Recvs().Fields().Slice() {
387                 funcarg2(f, ir.PPARAM)
388         }
389         for _, f := range t.Params().Fields().Slice() {
390                 funcarg2(f, ir.PPARAM)
391         }
392         for _, f := range t.Results().Fields().Slice() {
393                 funcarg2(f, ir.PPARAMOUT)
394         }
395 }
396
397 func Temp(t *types.Type) *ir.Name {
398         return TempAt(base.Pos, ir.CurFunc, t)
399 }
400
401 // make a new Node off the books
402 func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name {
403         if curfn == nil {
404                 base.Fatalf("no curfn for tempAt")
405         }
406         if curfn.Op() == ir.OCLOSURE {
407                 ir.Dump("tempAt", curfn)
408                 base.Fatalf("adding tempAt to wrong closure function")
409         }
410         if t == nil {
411                 base.Fatalf("tempAt called with nil type")
412         }
413         if t.Kind() == types.TFUNC && t.Recv() != nil {
414                 base.Fatalf("misuse of method type: %v", t)
415         }
416
417         s := &types.Sym{
418                 Name: autotmpname(len(curfn.Dcl)),
419                 Pkg:  types.LocalPkg,
420         }
421         n := ir.NewNameAt(pos, s)
422         s.Def = n
423         n.SetType(t)
424         n.Class = ir.PAUTO
425         n.SetEsc(ir.EscNever)
426         n.Curfn = curfn
427         n.SetUsed(true)
428         n.SetAutoTemp(true)
429         curfn.Dcl = append(curfn.Dcl, n)
430
431         types.CalcSize(t)
432
433         return n
434 }
435
436 // autotmpname returns the name for an autotmp variable numbered n.
437 func autotmpname(n int) string {
438         // Give each tmp a different name so that they can be registerized.
439         // Add a preceding . to avoid clashing with legal names.
440         const prefix = ".autotmp_"
441         // Start with a buffer big enough to hold a large n.
442         b := []byte(prefix + "      ")[:len(prefix)]
443         b = strconv.AppendInt(b, int64(n), 10)
444         return types.InternString(b)
445 }
446
447 // f is method type, with receiver.
448 // return function type, receiver as first argument (or not).
449 func NewMethodType(sig *types.Type, recv *types.Type) *types.Type {
450         nrecvs := 0
451         if recv != nil {
452                 nrecvs++
453         }
454
455         // TODO(mdempsky): Move this function to types.
456         // TODO(mdempsky): Preserve positions, names, and package from sig+recv.
457
458         params := make([]*types.Field, nrecvs+sig.Params().Fields().Len())
459         if recv != nil {
460                 params[0] = types.NewField(base.Pos, nil, recv)
461         }
462         for i, param := range sig.Params().Fields().Slice() {
463                 d := types.NewField(base.Pos, nil, param.Type)
464                 d.SetIsDDD(param.IsDDD())
465                 params[nrecvs+i] = d
466         }
467
468         results := make([]*types.Field, sig.Results().Fields().Len())
469         for i, t := range sig.Results().Fields().Slice() {
470                 results[i] = types.NewField(base.Pos, nil, t.Type)
471         }
472
473         return types.NewSignature(types.LocalPkg, nil, params, results)
474 }