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
5package noder
6
7import (
8	"go/constant"
9
10	"cmd/compile/internal/base"
11	"cmd/compile/internal/ir"
12	"cmd/compile/internal/syntax"
13	"cmd/compile/internal/typecheck"
14	"cmd/compile/internal/types"
15	"cmd/compile/internal/types2"
16)
17
18// TODO(mdempsky): Skip blank declarations? Probably only safe
19// for declarations without pragmas.
20
21func (g *irgen) decls(res *ir.Nodes, decls []syntax.Decl) {
22	for _, decl := range decls {
23		switch decl := decl.(type) {
24		case *syntax.ConstDecl:
25			g.constDecl(res, decl)
26		case *syntax.FuncDecl:
27			g.funcDecl(res, decl)
28		case *syntax.TypeDecl:
29			if ir.CurFunc == nil {
30				continue // already handled in irgen.generate
31			}
32			g.typeDecl(res, decl)
33		case *syntax.VarDecl:
34			g.varDecl(res, decl)
35		default:
36			g.unhandled("declaration", decl)
37		}
38	}
39}
40
41func (g *irgen) importDecl(p *noder, decl *syntax.ImportDecl) {
42	g.pragmaFlags(decl.Pragma, 0)
43
44	// Get the imported package's path, as resolved already by types2
45	// and gcimporter. This is the same path as would be computed by
46	// parseImportPath.
47	switch pkgNameOf(g.info, decl).Imported().Path() {
48	case "unsafe":
49		p.importedUnsafe = true
50	case "embed":
51		p.importedEmbed = true
52	}
53}
54
55// pkgNameOf returns the PkgName associated with the given ImportDecl.
56func pkgNameOf(info *types2.Info, decl *syntax.ImportDecl) *types2.PkgName {
57	if name := decl.LocalPkgName; name != nil {
58		return info.Defs[name].(*types2.PkgName)
59	}
60	return info.Implicits[decl].(*types2.PkgName)
61}
62
63func (g *irgen) constDecl(out *ir.Nodes, decl *syntax.ConstDecl) {
64	g.pragmaFlags(decl.Pragma, 0)
65
66	for _, name := range decl.NameList {
67		name, obj := g.def(name)
68
69		// For untyped numeric constants, make sure the value
70		// representation matches what the rest of the
71		// compiler (really just iexport) expects.
72		// TODO(mdempsky): Revisit after #43891 is resolved.
73		val := obj.(*types2.Const).Val()
74		switch name.Type() {
75		case types.UntypedInt, types.UntypedRune:
76			val = constant.ToInt(val)
77		case types.UntypedFloat:
78			val = constant.ToFloat(val)
79		case types.UntypedComplex:
80			val = constant.ToComplex(val)
81		}
82		name.SetVal(val)
83
84		out.Append(ir.NewDecl(g.pos(decl), ir.ODCLCONST, name))
85	}
86}
87
88func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
89	assert(g.curDecl == "")
90	// Set g.curDecl to the function name, as context for the type params declared
91	// during types2-to-types1 translation if this is a generic function.
92	g.curDecl = decl.Name.Value
93	obj2 := g.info.Defs[decl.Name]
94	recv := types2.AsSignature(obj2.Type()).Recv()
95	if recv != nil {
96		t2 := deref2(recv.Type())
97		// This is a method, so set g.curDecl to recvTypeName.methName instead.
98		g.curDecl = t2.(*types2.Named).Obj().Name() + "." + g.curDecl
99	}
100
101	fn := ir.NewFunc(g.pos(decl))
102	fn.Nname, _ = g.def(decl.Name)
103	fn.Nname.Func = fn
104	fn.Nname.Defn = fn
105
106	fn.Pragma = g.pragmaFlags(decl.Pragma, funcPragmas)
107	if fn.Pragma&ir.Systemstack != 0 && fn.Pragma&ir.Nosplit != 0 {
108		base.ErrorfAt(fn.Pos(), "go:nosplit and go:systemstack cannot be combined")
109	}
110	if fn.Pragma&ir.Nointerface != 0 {
111		// Propagate //go:nointerface from Func.Pragma to Field.Nointerface.
112		// This is a bit roundabout, but this is the earliest point where we've
113		// processed the function's pragma flags, and we've also already created
114		// the Fields to represent the receiver's method set.
115		if recv := fn.Type().Recv(); recv != nil {
116			typ := types.ReceiverBaseType(recv.Type)
117			if typ.OrigSym() != nil {
118				// For a generic method, we mark the methods on the
119				// base generic type, since those are the methods
120				// that will be stenciled.
121				typ = typ.OrigSym().Def.Type()
122			}
123			meth := typecheck.Lookdot1(fn, typecheck.Lookup(decl.Name.Value), typ, typ.Methods(), 0)
124			meth.SetNointerface(true)
125		}
126	}
127
128	if decl.Body != nil && fn.Pragma&ir.Noescape != 0 {
129		base.ErrorfAt(fn.Pos(), "can only use //go:noescape with external func implementations")
130	}
131
132	if decl.Name.Value == "init" && decl.Recv == nil {
133		g.target.Inits = append(g.target.Inits, fn)
134	}
135
136	haveEmbed := g.haveEmbed
137	g.curDecl = ""
138	g.later(func() {
139		defer func(b bool) { g.haveEmbed = b }(g.haveEmbed)
140
141		g.haveEmbed = haveEmbed
142		if fn.Type().HasTParam() {
143			g.topFuncIsGeneric = true
144		}
145		g.funcBody(fn, decl.Recv, decl.Type, decl.Body)
146		g.topFuncIsGeneric = false
147		if fn.Type().HasTParam() && fn.Body != nil {
148			// Set pointers to the dcls/body of a generic function/method in
149			// the Inl struct, so it is marked for export, is available for
150			// stenciling, and works with Inline_Flood().
151			fn.Inl = &ir.Inline{
152				Cost: 1,
153				Dcl:  fn.Dcl,
154				Body: fn.Body,
155			}
156		}
157
158		out.Append(fn)
159	})
160}
161
162func (g *irgen) typeDecl(out *ir.Nodes, decl *syntax.TypeDecl) {
163	// Set the position for any error messages we might print (e.g. too large types).
164	base.Pos = g.pos(decl)
165	assert(g.curDecl == "")
166	// Set g.curDecl to the type name, as context for the type params declared
167	// during types2-to-types1 translation if this is a generic type.
168	g.curDecl = decl.Name.Value
169	if decl.Alias {
170		name, _ := g.def(decl.Name)
171		g.pragmaFlags(decl.Pragma, 0)
172		assert(name.Alias()) // should be set by irgen.obj
173
174		out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name))
175		g.curDecl = ""
176		return
177	}
178
179	// Prevent size calculations until we set the underlying type.
180	types.DeferCheckSize()
181
182	name, obj := g.def(decl.Name)
183	ntyp, otyp := name.Type(), obj.Type()
184	if ir.CurFunc != nil {
185		ntyp.SetVargen()
186	}
187
188	pragmas := g.pragmaFlags(decl.Pragma, typePragmas)
189	name.SetPragma(pragmas) // TODO(mdempsky): Is this still needed?
190
191	if pragmas&ir.NotInHeap != 0 {
192		ntyp.SetNotInHeap(true)
193	}
194
195	// We need to use g.typeExpr(decl.Type) here to ensure that for
196	// chained, defined-type declarations like:
197	//
198	//	type T U
199	//
200	//	//go:notinheap
201	//	type U struct { … }
202	//
203	// we mark both T and U as NotInHeap. If we instead used just
204	// g.typ(otyp.Underlying()), then we'd instead set T's underlying
205	// type directly to the struct type (which is not marked NotInHeap)
206	// and fail to mark T as NotInHeap.
207	//
208	// Also, we rely here on Type.SetUnderlying allowing passing a
209	// defined type and handling forward references like from T to U
210	// above. Contrast with go/types's Named.SetUnderlying, which
211	// disallows this.
212	//
213	// [mdempsky: Subtleties like these are why I always vehemently
214	// object to new type pragmas.]
215	ntyp.SetUnderlying(g.typeExpr(decl.Type))
216
217	tparams := otyp.(*types2.Named).TypeParams()
218	if n := tparams.Len(); n > 0 {
219		rparams := make([]*types.Type, n)
220		for i := range rparams {
221			rparams[i] = g.typ(tparams.At(i))
222		}
223		// This will set hasTParam flag if any rparams are not concrete types.
224		ntyp.SetRParams(rparams)
225	}
226	types.ResumeCheckSize()
227
228	g.curDecl = ""
229	if otyp, ok := otyp.(*types2.Named); ok && otyp.NumMethods() != 0 {
230		methods := make([]*types.Field, otyp.NumMethods())
231		for i := range methods {
232			m := otyp.Method(i)
233			// Set g.curDecl to recvTypeName.methName, as context for the
234			// method-specific type params in the receiver.
235			g.curDecl = decl.Name.Value + "." + m.Name()
236			meth := g.obj(m)
237			methods[i] = types.NewField(meth.Pos(), g.selector(m), meth.Type())
238			methods[i].Nname = meth
239			g.curDecl = ""
240		}
241		ntyp.Methods().Set(methods)
242	}
243
244	out.Append(ir.NewDecl(g.pos(decl), ir.ODCLTYPE, name))
245}
246
247func (g *irgen) varDecl(out *ir.Nodes, decl *syntax.VarDecl) {
248	pos := g.pos(decl)
249	// Set the position for any error messages we might print (e.g. too large types).
250	base.Pos = pos
251	names := make([]*ir.Name, len(decl.NameList))
252	for i, name := range decl.NameList {
253		names[i], _ = g.def(name)
254	}
255
256	if decl.Pragma != nil {
257		pragma := decl.Pragma.(*pragmas)
258		varEmbed(g.makeXPos, names[0], decl, pragma, g.haveEmbed)
259		g.reportUnused(pragma)
260	}
261
262	haveEmbed := g.haveEmbed
263	do := func() {
264		defer func(b bool) { g.haveEmbed = b }(g.haveEmbed)
265
266		g.haveEmbed = haveEmbed
267		values := g.exprList(decl.Values)
268
269		var as2 *ir.AssignListStmt
270		if len(values) != 0 && len(names) != len(values) {
271			as2 = ir.NewAssignListStmt(pos, ir.OAS2, make([]ir.Node, len(names)), values)
272		}
273
274		for i, name := range names {
275			if ir.CurFunc != nil {
276				out.Append(ir.NewDecl(pos, ir.ODCL, name))
277			}
278			if as2 != nil {
279				as2.Lhs[i] = name
280				name.Defn = as2
281			} else {
282				as := ir.NewAssignStmt(pos, name, nil)
283				if len(values) != 0 {
284					as.Y = values[i]
285					name.Defn = as
286				} else if ir.CurFunc == nil {
287					name.Defn = as
288				}
289				if !g.delayTransform() {
290					lhs := []ir.Node{as.X}
291					rhs := []ir.Node{}
292					if as.Y != nil {
293						rhs = []ir.Node{as.Y}
294					}
295					transformAssign(as, lhs, rhs)
296					as.X = lhs[0]
297					if as.Y != nil {
298						as.Y = rhs[0]
299					}
300				}
301				as.SetTypecheck(1)
302				out.Append(as)
303			}
304		}
305		if as2 != nil {
306			if !g.delayTransform() {
307				transformAssign(as2, as2.Lhs, as2.Rhs)
308			}
309			as2.SetTypecheck(1)
310			out.Append(as2)
311		}
312	}
313
314	// If we're within a function, we need to process the assignment
315	// part of the variable declaration right away. Otherwise, we leave
316	// it to be handled after all top-level declarations are processed.
317	if ir.CurFunc != nil {
318		do()
319	} else {
320		g.later(do)
321	}
322}
323
324// pragmaFlags returns any specified pragma flags included in allowed,
325// and reports errors about any other, unexpected pragmas.
326func (g *irgen) pragmaFlags(pragma syntax.Pragma, allowed ir.PragmaFlag) ir.PragmaFlag {
327	if pragma == nil {
328		return 0
329	}
330	p := pragma.(*pragmas)
331	present := p.Flag & allowed
332	p.Flag &^= allowed
333	g.reportUnused(p)
334	return present
335}
336
337// reportUnused reports errors about any unused pragmas.
338func (g *irgen) reportUnused(pragma *pragmas) {
339	for _, pos := range pragma.Pos {
340		if pos.Flag&pragma.Flag != 0 {
341			base.ErrorfAt(g.makeXPos(pos.Pos), "misplaced compiler directive")
342		}
343	}
344	if len(pragma.Embeds) > 0 {
345		for _, e := range pragma.Embeds {
346			base.ErrorfAt(g.makeXPos(e.Pos), "misplaced go:embed directive")
347		}
348	}
349}
350