]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/typecheck/dcl.go
c25ea3448d1a94bba0c7fae511c18066835a9d0a
[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         "sync"
10
11         "cmd/compile/internal/base"
12         "cmd/compile/internal/ir"
13         "cmd/compile/internal/types"
14         "cmd/internal/src"
15 )
16
17 var funcStack []*ir.Func // stack of previous values of ir.CurFunc
18
19 // DeclFunc creates and returns ONAMEs for the parameters and results
20 // of the given function. It also sets ir.CurFunc, and adds fn to
21 // Target.Funcs.
22 //
23 // After the caller is done constructing fn, it must call
24 // FinishFuncBody.
25 func DeclFunc(fn *ir.Func) (params, results []*ir.Name) {
26         typ := fn.Type()
27
28         // Currently, DeclFunc is only used to create normal functions, not
29         // methods. If a use case for creating methods shows up, we can
30         // extend it to support those too.
31         if typ.Recv() != nil {
32                 base.FatalfAt(fn.Pos(), "unexpected receiver parameter")
33         }
34
35         params = declareParams(fn, ir.PPARAM, typ.Params())
36         results = declareParams(fn, ir.PPARAMOUT, typ.Results())
37
38         funcStack = append(funcStack, ir.CurFunc)
39         ir.CurFunc = fn
40
41         fn.Nname.Defn = fn
42         Target.Funcs = append(Target.Funcs, fn)
43
44         return
45 }
46
47 // FinishFuncBody restores ir.CurFunc to its state before the last
48 // call to DeclFunc.
49 func FinishFuncBody() {
50         funcStack, ir.CurFunc = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1]
51 }
52
53 func CheckFuncStack() {
54         if len(funcStack) != 0 {
55                 base.Fatalf("funcStack is non-empty: %v", len(funcStack))
56         }
57 }
58
59 func declareParams(fn *ir.Func, ctxt ir.Class, params []*types.Field) []*ir.Name {
60         names := make([]*ir.Name, len(params))
61         for i, param := range params {
62                 names[i] = declareParam(fn, ctxt, i, param)
63         }
64         return names
65 }
66
67 func declareParam(fn *ir.Func, ctxt ir.Class, i int, param *types.Field) *ir.Name {
68         sym := param.Sym
69         if ctxt == ir.PPARAMOUT {
70                 if sym == nil {
71                         // Name so that escape analysis can track it. ~r stands for 'result'.
72                         sym = LookupNum("~r", i)
73                 } else if sym.IsBlank() {
74                         // Give it a name so we can assign to it during return. ~b stands for 'blank'.
75                         // The name must be different from ~r above because if you have
76                         //      func f() (_ int)
77                         //      func g() int
78                         // f is allowed to use a plain 'return' with no arguments, while g is not.
79                         // So the two cases must be distinguished.
80                         sym = LookupNum("~b", i)
81                 }
82         }
83
84         if sym == nil {
85                 return nil
86         }
87
88         name := fn.NewLocal(param.Pos, sym, ctxt, param.Type)
89         param.Nname = name
90         return name
91 }
92
93 // make a new Node off the books.
94 func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name {
95         if curfn == nil {
96                 base.Fatalf("no curfn for TempAt")
97         }
98         if t == nil {
99                 base.Fatalf("TempAt called with nil type")
100         }
101         if t.Kind() == types.TFUNC && t.Recv() != nil {
102                 base.Fatalf("misuse of method type: %v", t)
103         }
104
105         s := &types.Sym{
106                 Name: autotmpname(len(curfn.Dcl)),
107                 Pkg:  types.LocalPkg,
108         }
109         n := curfn.NewLocal(pos, s, ir.PAUTO, t)
110         s.Def = n // TODO(mdempsky): Should be unnecessary.
111         n.SetEsc(ir.EscNever)
112         n.SetUsed(true)
113         n.SetAutoTemp(true)
114
115         types.CalcSize(t)
116
117         return n
118 }
119
120 var (
121         autotmpnamesmu sync.Mutex
122         autotmpnames   []string
123 )
124
125 // autotmpname returns the name for an autotmp variable numbered n.
126 func autotmpname(n int) string {
127         autotmpnamesmu.Lock()
128         defer autotmpnamesmu.Unlock()
129
130         // Grow autotmpnames, if needed.
131         if n >= len(autotmpnames) {
132                 autotmpnames = append(autotmpnames, make([]string, n+1-len(autotmpnames))...)
133                 autotmpnames = autotmpnames[:cap(autotmpnames)]
134         }
135
136         s := autotmpnames[n]
137         if s == "" {
138                 // Give each tmp a different name so that they can be registerized.
139                 // Add a preceding . to avoid clashing with legal names.
140                 prefix := ".autotmp_%d"
141
142                 s = fmt.Sprintf(prefix, n)
143                 autotmpnames[n] = s
144         }
145         return s
146 }
147
148 // f is method type, with receiver.
149 // return function type, receiver as first argument (or not).
150 func NewMethodType(sig *types.Type, recv *types.Type) *types.Type {
151         nrecvs := 0
152         if recv != nil {
153                 nrecvs++
154         }
155
156         // TODO(mdempsky): Move this function to types.
157         // TODO(mdempsky): Preserve positions, names, and package from sig+recv.
158
159         params := make([]*types.Field, nrecvs+sig.NumParams())
160         if recv != nil {
161                 params[0] = types.NewField(base.Pos, nil, recv)
162         }
163         for i, param := range sig.Params() {
164                 d := types.NewField(base.Pos, nil, param.Type)
165                 d.SetIsDDD(param.IsDDD())
166                 params[nrecvs+i] = d
167         }
168
169         results := make([]*types.Field, sig.NumResults())
170         for i, t := range sig.Results() {
171                 results[i] = types.NewField(base.Pos, nil, t.Type)
172         }
173
174         return types.NewSignature(nil, params, results)
175 }