]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/noder/decl.go
[dev.typeparams] cmd/compile: refactor irgen's handling of ":="
[gostls13.git] / src / cmd / compile / internal / noder / decl.go
1 // Copyright 2021 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 noder
6
7 import (
8         "cmd/compile/internal/base"
9         "cmd/compile/internal/ir"
10         "cmd/compile/internal/syntax"
11         "cmd/compile/internal/typecheck"
12         "cmd/compile/internal/types"
13         "cmd/compile/internal/types2"
14 )
15
16 // TODO(mdempsky): Skip blank declarations? Probably only safe
17 // for declarations without pragmas.
18
19 func (g *irgen) decls(decls []syntax.Decl) []ir.Node {
20         var res ir.Nodes
21         for _, decl := range decls {
22                 switch decl := decl.(type) {
23                 case *syntax.ConstDecl:
24                         g.constDecl(&res, decl)
25                 case *syntax.FuncDecl:
26                         g.funcDecl(&res, decl)
27                 case *syntax.TypeDecl:
28                         if ir.CurFunc == nil {
29                                 continue // already handled in irgen.generate
30                         }
31                         g.typeDecl(&res, decl)
32                 case *syntax.VarDecl:
33                         g.varDecl(&res, decl)
34                 default:
35                         g.unhandled("declaration", decl)
36                 }
37         }
38         return res
39 }
40
41 func (g *irgen) importDecl(p *noder, decl *syntax.ImportDecl) {
42         // TODO(mdempsky): Merge with gcimports so we don't have to import
43         // packages twice.
44
45         g.pragmaFlags(decl.Pragma, 0)
46
47         ipkg := importfile(decl)
48         if ipkg == ir.Pkgs.Unsafe {
49                 p.importedUnsafe = true
50         }
51 }
52
53 func (g *irgen) constDecl(out *ir.Nodes, decl *syntax.ConstDecl) {
54         g.pragmaFlags(decl.Pragma, 0)
55
56         for _, name := range decl.NameList {
57                 name, obj := g.def(name)
58                 name.SetVal(obj.(*types2.Const).Val())
59                 out.Append(ir.NewDecl(g.pos(decl), ir.ODCLCONST, name))
60         }
61 }
62
63 func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
64         fn := ir.NewFunc(g.pos(decl))
65         fn.Nname, _ = g.def(decl.Name)
66         fn.Nname.Func = fn
67         fn.Nname.Defn = fn
68
69         fn.Pragma = g.pragmaFlags(decl.Pragma, funcPragmas)
70         if fn.Pragma&ir.Systemstack != 0 && fn.Pragma&ir.Nosplit != 0 {
71                 base.ErrorfAt(fn.Pos(), "go:nosplit and go:systemstack cannot be combined")
72         }
73
74         if decl.Name.Value == "init" && decl.Recv == nil {
75                 g.target.Inits = append(g.target.Inits, fn)
76         }
77
78         g.funcBody(fn, decl.Recv, decl.Type, decl.Body)
79
80         out.Append(fn)
81 }
82
83 func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
84         if decl.Alias {
85                 if !types.AllowsGoVersion(types.LocalPkg, 1, 9) {
86                         base.ErrorfAt(g.pos(decl), "type aliases only supported as of -lang=go1.9")
87                 }
88
89                 name, _ := g.def(decl.Name)
90                 g.pragmaFlags(decl.Pragma, 0)
91
92                 // TODO(mdempsky): This matches how typecheckdef marks aliases for
93                 // export, but this won't generalize to exporting function-scoped
94                 // type aliases. We should maybe just use n.Alias() instead.
95                 if ir.CurFunc == nil {
96                         name.Sym().Def = ir.TypeNode(name.Type())
97                 }
98
99                 out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name))
100                 return
101         }
102
103         // Prevent size calculations until we set the underlying type.
104         types.DeferCheckSize()
105
106         name, obj := g.def(decl.Name)
107         ntyp, otyp := name.Type(), obj.Type()
108         if ir.CurFunc != nil {
109                 typecheck.TypeGen++
110                 ntyp.Vargen = typecheck.TypeGen
111         }
112
113         pragmas := g.pragmaFlags(decl.Pragma, typePragmas)
114         name.SetPragma(pragmas) // TODO(mdempsky): Is this still needed?
115
116         if pragmas&ir.NotInHeap != 0 {
117                 ntyp.SetNotInHeap(true)
118         }
119
120         // We need to use g.typeExpr(decl.Type) here to ensure that for
121         // chained, defined-type declarations like
122         //
123         //      type T U
124         //
125         //      //go:notinheap
126         //      type U struct { … }
127         //
128         // that we mark both T and U as NotInHeap. If we instead used just
129         // g.typ(otyp.Underlying()), then we'd instead set T's underlying
130         // type directly to the struct type (which is not marked NotInHeap)
131         // and fail to mark T as NotInHeap.
132         //
133         // Also, we rely here on Type.SetUnderlying allowing passing a
134         // defined type and handling forward references like from T to U
135         // above. Contrast with go/types's Named.SetUnderlying, which
136         // disallows this.
137         //
138         // [mdempsky: Subtleties like these are why I always vehemently
139         // object to new type pragmas.]
140         ntyp.SetUnderlying(g.typeExpr(decl.Type))
141         types.ResumeCheckSize()
142
143         if otyp, ok := otyp.(*types2.Named); ok && otyp.NumMethods() != 0 {
144                 methods := make([]*types.Field, otyp.NumMethods())
145                 for i := range methods {
146                         m := otyp.Method(i)
147                         meth := g.obj(m)
148                         methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
149                         methods[i].Nname = meth
150                 }
151                 ntyp.Methods().Set(methods)
152         }
153
154         out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name))
155 }
156
157 func (g *irgen) varDecl(out *ir.Nodes, decl *syntax.VarDecl) {
158         pos := g.pos(decl)
159         names := make([]*ir.Name, len(decl.NameList))
160         for i, name := range decl.NameList {
161                 names[i], _ = g.def(name)
162         }
163         values := g.exprList(decl.Values)
164
165         if decl.Pragma != nil {
166                 pragma := decl.Pragma.(*pragmas)
167                 if err := varEmbed(g.makeXPos, names[0], decl, pragma); err != nil {
168                         base.ErrorfAt(g.pos(decl), "%s", err.Error())
169                 }
170                 g.reportUnused(pragma)
171         }
172
173         var as2 *ir.AssignListStmt
174         if len(values) != 0 && len(names) != len(values) {
175                 as2 = ir.NewAssignListStmt(pos, ir.OAS2, make([]ir.Node, len(names)), values)
176         }
177
178         for i, name := range names {
179                 if ir.CurFunc != nil {
180                         out.Append(ir.NewDecl(pos, ir.ODCL, name))
181                 }
182                 if as2 != nil {
183                         as2.Lhs[i] = name
184                         name.Defn = as2
185                 } else {
186                         as := ir.NewAssignStmt(pos, name, nil)
187                         if len(values) != 0 {
188                                 as.Y = values[i]
189                                 name.Defn = as
190                         } else if ir.CurFunc == nil {
191                                 name.Defn = as
192                         }
193                         out.Append(typecheck.Stmt(as))
194                 }
195         }
196         if as2 != nil {
197                 out.Append(typecheck.Stmt(as2))
198         }
199 }
200
201 // pragmaFlags returns any specified pragma flags included in allowed,
202 // and reports errors about any other, unexpected pragmas.
203 func (g *irgen) pragmaFlags(pragma syntax.Pragma, allowed ir.PragmaFlag) ir.PragmaFlag {
204         if pragma == nil {
205                 return 0
206         }
207         p := pragma.(*pragmas)
208         present := p.Flag & allowed
209         p.Flag &^= allowed
210         g.reportUnused(p)
211         return present
212 }
213
214 // reportUnused reports errors about any unused pragmas.
215 func (g *irgen) reportUnused(pragma *pragmas) {
216         for _, pos := range pragma.Pos {
217                 if pos.Flag&pragma.Flag != 0 {
218                         base.ErrorfAt(g.makeXPos(pos.Pos), "misplaced compiler directive")
219                 }
220         }
221         if len(pragma.Embeds) > 0 {
222                 for _, e := range pragma.Embeds {
223                         base.ErrorfAt(g.makeXPos(e.Pos), "misplaced go:embed directive")
224                 }
225         }
226 }