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/typecheck"
13	"cmd/compile/internal/types"
14	"cmd/internal/src"
15)
16
17// Helpers for constructing typed IR nodes.
18//
19// TODO(mdempsky): Move into their own package so they can be easily
20// reused by iimport and frontend optimizations.
21
22type ImplicitNode interface {
23	ir.Node
24	SetImplicit(x bool)
25}
26
27// Implicit returns n after marking it as Implicit.
28func Implicit(n ImplicitNode) ImplicitNode {
29	n.SetImplicit(true)
30	return n
31}
32
33// typed returns n after setting its type to typ.
34func typed(typ *types.Type, n ir.Node) ir.Node {
35	n.SetType(typ)
36	n.SetTypecheck(1)
37	return n
38}
39
40// Values
41
42func Const(pos src.XPos, typ *types.Type, val constant.Value) ir.Node {
43	return typed(typ, ir.NewBasicLit(pos, val))
44}
45
46func OrigConst(pos src.XPos, typ *types.Type, val constant.Value, op ir.Op, raw string) ir.Node {
47	orig := ir.NewRawOrigExpr(pos, op, raw)
48	return ir.NewConstExpr(val, typed(typ, orig))
49}
50
51// FixValue returns val after converting and truncating it as
52// appropriate for typ.
53func FixValue(typ *types.Type, val constant.Value) constant.Value {
54	assert(typ.Kind() != types.TFORW)
55	switch {
56	case typ.IsInteger():
57		val = constant.ToInt(val)
58	case typ.IsFloat():
59		val = constant.ToFloat(val)
60	case typ.IsComplex():
61		val = constant.ToComplex(val)
62	}
63	if !typ.IsUntyped() {
64		val = typecheck.DefaultLit(ir.NewBasicLit(src.NoXPos, val), typ).Val()
65	}
66	if !typ.IsTypeParam() {
67		ir.AssertValidTypeForConst(typ, val)
68	}
69	return val
70}
71
72func Nil(pos src.XPos, typ *types.Type) ir.Node {
73	return typed(typ, ir.NewNilExpr(pos))
74}
75
76// Expressions
77
78func Addr(pos src.XPos, x ir.Node) *ir.AddrExpr {
79	n := typecheck.NodAddrAt(pos, x)
80	typed(types.NewPtr(x.Type()), n)
81	return n
82}
83
84func Assert(pos src.XPos, x ir.Node, typ *types.Type) ir.Node {
85	return typed(typ, ir.NewTypeAssertExpr(pos, x, nil))
86}
87
88func Binary(pos src.XPos, op ir.Op, typ *types.Type, x, y ir.Node) *ir.BinaryExpr {
89	switch op {
90	case ir.OADD:
91		n := ir.NewBinaryExpr(pos, op, x, y)
92		typed(typ, n)
93		return n
94	default:
95		n := ir.NewBinaryExpr(pos, op, x, y)
96		typed(x.Type(), n)
97		return n
98	}
99}
100
101func Call(pos src.XPos, typ *types.Type, fun ir.Node, args []ir.Node, dots bool) ir.Node {
102	n := ir.NewCallExpr(pos, ir.OCALL, fun, args)
103	n.IsDDD = dots
104
105	if fun.Op() == ir.OTYPE {
106		// Actually a type conversion, not a function call.
107		if !fun.Type().IsInterface() &&
108			(fun.Type().HasTParam() || args[0].Type().HasTParam()) {
109			// For type params, we can transform if fun.Type() is known
110			// to be an interface (in which case a CONVIFACE node will be
111			// inserted). Otherwise, don't typecheck until we actually
112			// know the type.
113			return typed(typ, n)
114		}
115		typed(typ, n)
116		return transformConvCall(n)
117	}
118
119	if fun, ok := fun.(*ir.Name); ok && fun.BuiltinOp != 0 {
120		// For most Builtin ops, we delay doing transformBuiltin if any of the
121		// args have type params, for a variety of reasons:
122		//
123		// OMAKE: transformMake can't choose specific ops OMAKESLICE, etc.
124		//    until arg type is known
125		// OREAL/OIMAG: transformRealImag can't determine type float32/float64
126		//    until arg type known
127		// OAPPEND: transformAppend requires that the arg is a slice
128		// ODELETE: transformDelete requires that the arg is a map
129		// OALIGNOF, OSIZEOF: can be eval'ed to a constant until types known.
130		switch fun.BuiltinOp {
131		case ir.OMAKE, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.ODELETE, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
132			hasTParam := false
133			for _, arg := range args {
134				if fun.BuiltinOp == ir.OOFFSETOF {
135					// It's the type of left operand of the
136					// selection that matters, not the type of
137					// the field itself (which is irrelevant for
138					// offsetof).
139					arg = arg.(*ir.SelectorExpr).X
140				}
141				if arg.Type().HasTParam() {
142					hasTParam = true
143					break
144				}
145			}
146			if hasTParam {
147				return typed(typ, n)
148			}
149		}
150
151		typed(typ, n)
152		return transformBuiltin(n)
153	}
154
155	// Add information, now that we know that fun is actually being called.
156	switch fun := fun.(type) {
157	case *ir.SelectorExpr:
158		if fun.Op() == ir.OMETHVALUE {
159			op := ir.ODOTMETH
160			if fun.X.Type().IsInterface() {
161				op = ir.ODOTINTER
162			}
163			fun.SetOp(op)
164			// Set the type to include the receiver, since that's what
165			// later parts of the compiler expect
166			fun.SetType(fun.Selection.Type)
167		}
168	}
169
170	if fun.Type().HasTParam() || fun.Op() == ir.OXDOT || fun.Op() == ir.OFUNCINST {
171		// If the fun arg is or has a type param, we can't do all the
172		// transformations, since we may not have needed properties yet
173		// (e.g. number of return values, etc). The same applies if a fun
174		// which is an XDOT could not be transformed yet because of a generic
175		// type in the X of the selector expression.
176		//
177		// A function instantiation (even if fully concrete) shouldn't be
178		// transformed yet, because we need to add the dictionary during the
179		// transformation.
180		return typed(typ, n)
181	}
182
183	// If no type params, do the normal call transformations. This
184	// will convert OCALL to OCALLFUNC.
185	typed(typ, n)
186	transformCall(n)
187	return n
188}
189
190func Compare(pos src.XPos, typ *types.Type, op ir.Op, x, y ir.Node) *ir.BinaryExpr {
191	n := ir.NewBinaryExpr(pos, op, x, y)
192	typed(typ, n)
193	return n
194}
195
196func Deref(pos src.XPos, typ *types.Type, x ir.Node) *ir.StarExpr {
197	n := ir.NewStarExpr(pos, x)
198	typed(typ, n)
199	return n
200}
201
202func DotField(pos src.XPos, x ir.Node, index int) *ir.SelectorExpr {
203	op, typ := ir.ODOT, x.Type()
204	if typ.IsPtr() {
205		op, typ = ir.ODOTPTR, typ.Elem()
206	}
207	if !typ.IsStruct() {
208		base.FatalfAt(pos, "DotField of non-struct: %L", x)
209	}
210
211	// TODO(mdempsky): This is the backend's responsibility.
212	types.CalcSize(typ)
213
214	field := typ.Field(index)
215	return dot(pos, field.Type, op, x, field)
216}
217
218func DotMethod(pos src.XPos, x ir.Node, index int) *ir.SelectorExpr {
219	method := method(x.Type(), index)
220
221	// Method value.
222	typ := typecheck.NewMethodType(method.Type, nil)
223	return dot(pos, typ, ir.OMETHVALUE, x, method)
224}
225
226// MethodExpr returns a OMETHEXPR node with the indicated index into the methods
227// of typ. The receiver type is set from recv, which is different from typ if the
228// method was accessed via embedded fields. Similarly, the X value of the
229// ir.SelectorExpr is recv, the original OTYPE node before passing through the
230// embedded fields.
231func MethodExpr(pos src.XPos, recv ir.Node, embed *types.Type, index int) *ir.SelectorExpr {
232	method := method(embed, index)
233	typ := typecheck.NewMethodType(method.Type, recv.Type())
234	// The method expression T.m requires a wrapper when T
235	// is different from m's declared receiver type. We
236	// normally generate these wrappers while writing out
237	// runtime type descriptors, which is always done for
238	// types declared at package scope. However, we need
239	// to make sure to generate wrappers for anonymous
240	// receiver types too.
241	if recv.Sym() == nil {
242		typecheck.NeedRuntimeType(recv.Type())
243	}
244	return dot(pos, typ, ir.OMETHEXPR, recv, method)
245}
246
247func dot(pos src.XPos, typ *types.Type, op ir.Op, x ir.Node, selection *types.Field) *ir.SelectorExpr {
248	n := ir.NewSelectorExpr(pos, op, x, selection.Sym)
249	n.Selection = selection
250	typed(typ, n)
251	return n
252}
253
254// TODO(mdempsky): Move to package types.
255func method(typ *types.Type, index int) *types.Field {
256	if typ.IsInterface() {
257		return typ.AllMethods().Index(index)
258	}
259	return types.ReceiverBaseType(typ).Methods().Index(index)
260}
261
262func Index(pos src.XPos, typ *types.Type, x, index ir.Node) *ir.IndexExpr {
263	n := ir.NewIndexExpr(pos, x, index)
264	typed(typ, n)
265	return n
266}
267
268func Slice(pos src.XPos, typ *types.Type, x, low, high, max ir.Node) *ir.SliceExpr {
269	op := ir.OSLICE
270	if max != nil {
271		op = ir.OSLICE3
272	}
273	n := ir.NewSliceExpr(pos, op, x, low, high, max)
274	typed(typ, n)
275	return n
276}
277
278func Unary(pos src.XPos, typ *types.Type, op ir.Op, x ir.Node) ir.Node {
279	switch op {
280	case ir.OADDR:
281		return Addr(pos, x)
282	case ir.ODEREF:
283		return Deref(pos, typ, x)
284	}
285
286	if op == ir.ORECV {
287		if typ.IsFuncArgStruct() && typ.NumFields() == 2 {
288			// Remove the second boolean type (if provided by type2),
289			// since that works better with the rest of the compiler
290			// (which will add it back in later).
291			assert(typ.Field(1).Type.Kind() == types.TBOOL)
292			typ = typ.Field(0).Type
293		}
294	}
295	return typed(typ, ir.NewUnaryExpr(pos, op, x))
296}
297
298// Statements
299
300var one = constant.MakeInt64(1)
301
302func IncDec(pos src.XPos, op ir.Op, x ir.Node) *ir.AssignOpStmt {
303	assert(x.Type() != nil)
304	bl := ir.NewBasicLit(pos, one)
305	if x.Type().HasTParam() {
306		// If the operand is generic, then types2 will have proved it must be
307		// a type that fits with increment/decrement, so just set the type of
308		// "one" to n.Type(). This works even for types that are eventually
309		// float or complex.
310		typed(x.Type(), bl)
311	} else {
312		bl = typecheck.DefaultLit(bl, x.Type())
313	}
314	return ir.NewAssignOpStmt(pos, op, x, bl)
315}
316