1// Copyright 2022 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 reflectdata
6
7import (
8	"cmd/compile/internal/base"
9	"cmd/compile/internal/ir"
10	"cmd/compile/internal/types"
11	"cmd/internal/src"
12)
13
14func hasRType(n, rtype ir.Node, fieldName string) bool {
15	if rtype != nil {
16		return true
17	}
18
19	return false
20}
21
22// assertOp asserts that n is an op.
23func assertOp(n ir.Node, op ir.Op) {
24	base.AssertfAt(n.Op() == op, n.Pos(), "want %v, have %v", op, n)
25}
26
27// assertOp2 asserts that n is an op1 or op2.
28func assertOp2(n ir.Node, op1, op2 ir.Op) {
29	base.AssertfAt(n.Op() == op1 || n.Op() == op2, n.Pos(), "want %v or %v, have %v", op1, op2, n)
30}
31
32// kindRType asserts that typ has the given kind, and returns an
33// expression that yields the *runtime._type value representing typ.
34func kindRType(pos src.XPos, typ *types.Type, k types.Kind) ir.Node {
35	base.AssertfAt(typ.Kind() == k, pos, "want %v type, have %v", k, typ)
36	return TypePtrAt(pos, typ)
37}
38
39// mapRType asserts that typ is a map type, and returns an expression
40// that yields the *runtime._type value representing typ.
41func mapRType(pos src.XPos, typ *types.Type) ir.Node {
42	return kindRType(pos, typ, types.TMAP)
43}
44
45// chanRType asserts that typ is a map type, and returns an expression
46// that yields the *runtime._type value representing typ.
47func chanRType(pos src.XPos, typ *types.Type) ir.Node {
48	return kindRType(pos, typ, types.TCHAN)
49}
50
51// sliceElemRType asserts that typ is a slice type, and returns an
52// expression that yields the *runtime._type value representing typ's
53// element type.
54func sliceElemRType(pos src.XPos, typ *types.Type) ir.Node {
55	base.AssertfAt(typ.IsSlice(), pos, "want slice type, have %v", typ)
56	return TypePtrAt(pos, typ.Elem())
57}
58
59// concreteRType asserts that typ is not an interface type, and
60// returns an expression that yields the *runtime._type value
61// representing typ.
62func concreteRType(pos src.XPos, typ *types.Type) ir.Node {
63	base.AssertfAt(!typ.IsInterface(), pos, "want non-interface type, have %v", typ)
64	return TypePtrAt(pos, typ)
65}
66
67// AppendElemRType asserts that n is an "append" operation, and
68// returns an expression that yields the *runtime._type value
69// representing the result slice type's element type.
70func AppendElemRType(pos src.XPos, n *ir.CallExpr) ir.Node {
71	assertOp(n, ir.OAPPEND)
72	if hasRType(n, n.RType, "RType") {
73		return n.RType
74	}
75	return sliceElemRType(pos, n.Type())
76}
77
78// CompareRType asserts that n is a comparison (== or !=) operation
79// between expressions of interface and non-interface type, and
80// returns an expression that yields the *runtime._type value
81// representing the non-interface type.
82func CompareRType(pos src.XPos, n *ir.BinaryExpr) ir.Node {
83	assertOp2(n, ir.OEQ, ir.ONE)
84	base.AssertfAt(n.X.Type().IsInterface() != n.Y.Type().IsInterface(), n.Pos(), "expect mixed interface and non-interface, have %L and %L", n.X, n.Y)
85	if hasRType(n, n.RType, "RType") {
86		return n.RType
87	}
88	typ := n.X.Type()
89	if typ.IsInterface() {
90		typ = n.Y.Type()
91	}
92	return concreteRType(pos, typ)
93}
94
95// ConvIfaceTypeWord asserts that n is conversion to interface type,
96// and returns an expression that yields the *runtime._type or
97// *runtime.itab value necessary for implementing the conversion.
98//
99//   - *runtime._type for the destination type, for I2I conversions
100//   - *runtime.itab, for T2I conversions
101//   - *runtime._type for the source type, for T2E conversions
102func ConvIfaceTypeWord(pos src.XPos, n *ir.ConvExpr) ir.Node {
103	assertOp(n, ir.OCONVIFACE)
104	src, dst := n.X.Type(), n.Type()
105	base.AssertfAt(dst.IsInterface(), n.Pos(), "want interface type, have %L", n)
106	if hasRType(n, n.TypeWord, "TypeWord") {
107		return n.TypeWord
108	}
109	if dst.IsEmptyInterface() {
110		return concreteRType(pos, src) // direct eface construction
111	}
112	if !src.IsInterface() {
113		return ITabAddrAt(pos, src, dst) // direct iface construction
114	}
115	return TypePtrAt(pos, dst) // convI2I
116}
117
118// ConvIfaceSrcRType asserts that n is a conversion from
119// non-interface type to interface type, and
120// returns an expression that yields the *runtime._type for copying
121// the convertee value to the heap.
122func ConvIfaceSrcRType(pos src.XPos, n *ir.ConvExpr) ir.Node {
123	assertOp(n, ir.OCONVIFACE)
124	if hasRType(n, n.SrcRType, "SrcRType") {
125		return n.SrcRType
126	}
127	return concreteRType(pos, n.X.Type())
128}
129
130// CopyElemRType asserts that n is a "copy" operation, and returns an
131// expression that yields the *runtime._type value representing the
132// destination slice type's element type.
133func CopyElemRType(pos src.XPos, n *ir.BinaryExpr) ir.Node {
134	assertOp(n, ir.OCOPY)
135	if hasRType(n, n.RType, "RType") {
136		return n.RType
137	}
138	return sliceElemRType(pos, n.X.Type())
139}
140
141// DeleteMapRType asserts that n is a "delete" operation, and returns
142// an expression that yields the *runtime._type value representing the
143// map type.
144func DeleteMapRType(pos src.XPos, n *ir.CallExpr) ir.Node {
145	assertOp(n, ir.ODELETE)
146	if hasRType(n, n.RType, "RType") {
147		return n.RType
148	}
149	return mapRType(pos, n.Args[0].Type())
150}
151
152// IndexMapRType asserts that n is a map index operation, and returns
153// an expression that yields the *runtime._type value representing the
154// map type.
155func IndexMapRType(pos src.XPos, n *ir.IndexExpr) ir.Node {
156	assertOp(n, ir.OINDEXMAP)
157	if hasRType(n, n.RType, "RType") {
158		return n.RType
159	}
160	return mapRType(pos, n.X.Type())
161}
162
163// MakeChanRType asserts that n is a "make" operation for a channel
164// type, and returns an expression that yields the *runtime._type
165// value representing that channel type.
166func MakeChanRType(pos src.XPos, n *ir.MakeExpr) ir.Node {
167	assertOp(n, ir.OMAKECHAN)
168	if hasRType(n, n.RType, "RType") {
169		return n.RType
170	}
171	return chanRType(pos, n.Type())
172}
173
174// MakeMapRType asserts that n is a "make" operation for a map type,
175// and returns an expression that yields the *runtime._type value
176// representing that map type.
177func MakeMapRType(pos src.XPos, n *ir.MakeExpr) ir.Node {
178	assertOp(n, ir.OMAKEMAP)
179	if hasRType(n, n.RType, "RType") {
180		return n.RType
181	}
182	return mapRType(pos, n.Type())
183}
184
185// MakeSliceElemRType asserts that n is a "make" operation for a slice
186// type, and returns an expression that yields the *runtime._type
187// value representing that slice type's element type.
188func MakeSliceElemRType(pos src.XPos, n *ir.MakeExpr) ir.Node {
189	assertOp2(n, ir.OMAKESLICE, ir.OMAKESLICECOPY)
190	if hasRType(n, n.RType, "RType") {
191		return n.RType
192	}
193	return sliceElemRType(pos, n.Type())
194}
195
196// RangeMapRType asserts that n is a "range" loop over a map value,
197// and returns an expression that yields the *runtime._type value
198// representing that map type.
199func RangeMapRType(pos src.XPos, n *ir.RangeStmt) ir.Node {
200	assertOp(n, ir.ORANGE)
201	if hasRType(n, n.RType, "RType") {
202		return n.RType
203	}
204	return mapRType(pos, n.X.Type())
205}
206
207// UnsafeSliceElemRType asserts that n is an "unsafe.Slice" operation,
208// and returns an expression that yields the *runtime._type value
209// representing the result slice type's element type.
210func UnsafeSliceElemRType(pos src.XPos, n *ir.BinaryExpr) ir.Node {
211	assertOp(n, ir.OUNSAFESLICE)
212	if hasRType(n, n.RType, "RType") {
213		return n.RType
214	}
215	return sliceElemRType(pos, n.Type())
216}
217