aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/reflectdata/helpers.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/reflectdata/helpers.go')
-rw-r--r--src/cmd/compile/internal/reflectdata/helpers.go226
1 files changed, 226 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/reflectdata/helpers.go b/src/cmd/compile/internal/reflectdata/helpers.go
new file mode 100644
index 0000000000..99461cff52
--- /dev/null
+++ b/src/cmd/compile/internal/reflectdata/helpers.go
@@ -0,0 +1,226 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package reflectdata
+
+import (
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
+)
+
+func hasRType(n, rtype ir.Node, fieldName string) bool {
+ if rtype != nil {
+ return true
+ }
+
+ // We make an exception for `init`, because we still depend on
+ // pkginit for sorting package initialization statements, and it
+ // gets confused by implicit conversions. Also, because
+ // package-scope statements can never be generic, so they'll never
+ // require dictionary lookups.
+ if base.Debug.Unified != 0 && ir.CurFunc.Nname.Sym().Name != "init" {
+ ir.Dump("CurFunc", ir.CurFunc)
+ base.FatalfAt(n.Pos(), "missing %s in %v: %+v", fieldName, ir.CurFunc, n)
+ }
+
+ return false
+}
+
+// assertOp asserts that n is an op.
+func assertOp(n ir.Node, op ir.Op) {
+ base.AssertfAt(n.Op() == op, n.Pos(), "want %v, have %v", op, n)
+}
+
+// assertOp2 asserts that n is an op1 or op2.
+func assertOp2(n ir.Node, op1, op2 ir.Op) {
+ base.AssertfAt(n.Op() == op1 || n.Op() == op2, n.Pos(), "want %v or %v, have %v", op1, op2, n)
+}
+
+// kindRType asserts that typ has the given kind, and returns an
+// expression that yields the *runtime._type value representing typ.
+func kindRType(pos src.XPos, typ *types.Type, k types.Kind) ir.Node {
+ base.AssertfAt(typ.Kind() == k, pos, "want %v type, have %v", k, typ)
+ return TypePtrAt(pos, typ)
+}
+
+// mapRType asserts that typ is a map type, and returns an expression
+// that yields the *runtime._type value representing typ.
+func mapRType(pos src.XPos, typ *types.Type) ir.Node {
+ return kindRType(pos, typ, types.TMAP)
+}
+
+// chanRType asserts that typ is a map type, and returns an expression
+// that yields the *runtime._type value representing typ.
+func chanRType(pos src.XPos, typ *types.Type) ir.Node {
+ return kindRType(pos, typ, types.TCHAN)
+}
+
+// sliceElemRType asserts that typ is a slice type, and returns an
+// expression that yields the *runtime._type value representing typ's
+// element type.
+func sliceElemRType(pos src.XPos, typ *types.Type) ir.Node {
+ base.AssertfAt(typ.IsSlice(), pos, "want slice type, have %v", typ)
+ return TypePtrAt(pos, typ.Elem())
+}
+
+// concreteRType asserts that typ is not an interface type, and
+// returns an expression that yields the *runtime._type value
+// representing typ.
+func concreteRType(pos src.XPos, typ *types.Type) ir.Node {
+ base.AssertfAt(!typ.IsInterface(), pos, "want non-interface type, have %v", typ)
+ return TypePtrAt(pos, typ)
+}
+
+// AppendElemRType asserts that n is an "append" operation, and
+// returns an expression that yields the *runtime._type value
+// representing the result slice type's element type.
+func AppendElemRType(pos src.XPos, n *ir.CallExpr) ir.Node {
+ assertOp(n, ir.OAPPEND)
+ if hasRType(n, n.RType, "RType") {
+ return n.RType
+ }
+ return sliceElemRType(pos, n.Type())
+}
+
+// CompareRType asserts that n is a comparison (== or !=) operation
+// between expressions of interface and non-interface type, and
+// returns an expression that yields the *runtime._type value
+// representing the non-interface type.
+func CompareRType(pos src.XPos, n *ir.BinaryExpr) ir.Node {
+ assertOp2(n, ir.OEQ, ir.ONE)
+ 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)
+ if hasRType(n, n.RType, "RType") {
+ return n.RType
+ }
+ typ := n.X.Type()
+ if typ.IsInterface() {
+ typ = n.Y.Type()
+ }
+ return concreteRType(pos, typ)
+}
+
+// ConvIfaceTypeWord asserts that n is conversion to interface type,
+// and returns an expression that yields the *runtime._type or
+// *runtime.itab value necessary for implementing the conversion.
+//
+// - *runtime._type for the destination type, for I2I conversions
+// - *runtime.itab, for T2I conversions
+// - *runtime._type for the source type, for T2E conversions
+func ConvIfaceTypeWord(pos src.XPos, n *ir.ConvExpr) ir.Node {
+ assertOp(n, ir.OCONVIFACE)
+ src, dst := n.X.Type(), n.Type()
+ base.AssertfAt(dst.IsInterface(), n.Pos(), "want interface type, have %L", n)
+ if hasRType(n, n.TypeWord, "TypeWord") {
+ return n.TypeWord
+ }
+ if dst.IsEmptyInterface() {
+ return concreteRType(pos, src) // direct eface construction
+ }
+ if !src.IsInterface() {
+ return ITabAddrAt(pos, src, dst) // direct iface construction
+ }
+ return TypePtrAt(pos, dst) // convI2I
+}
+
+// ConvIfaceSrcRType asserts that n is a conversion from
+// non-interface type to interface type (or OCONVIDATA operation), and
+// returns an expression that yields the *runtime._type for copying
+// the convertee value to the heap.
+func ConvIfaceSrcRType(pos src.XPos, n *ir.ConvExpr) ir.Node {
+ assertOp2(n, ir.OCONVIFACE, ir.OCONVIDATA)
+ if hasRType(n, n.SrcRType, "SrcRType") {
+ return n.SrcRType
+ }
+ return concreteRType(pos, n.X.Type())
+}
+
+// CopyElemRType asserts that n is a "copy" operation, and returns an
+// expression that yields the *runtime._type value representing the
+// destination slice type's element type.
+func CopyElemRType(pos src.XPos, n *ir.BinaryExpr) ir.Node {
+ assertOp(n, ir.OCOPY)
+ if hasRType(n, n.RType, "RType") {
+ return n.RType
+ }
+ return sliceElemRType(pos, n.X.Type())
+}
+
+// DeleteMapRType asserts that n is a "delete" operation, and returns
+// an expression that yields the *runtime._type value representing the
+// map type.
+func DeleteMapRType(pos src.XPos, n *ir.CallExpr) ir.Node {
+ assertOp(n, ir.ODELETE)
+ if hasRType(n, n.RType, "RType") {
+ return n.RType
+ }
+ return mapRType(pos, n.Args[0].Type())
+}
+
+// IndexMapRType asserts that n is a map index operation, and returns
+// an expression that yields the *runtime._type value representing the
+// map type.
+func IndexMapRType(pos src.XPos, n *ir.IndexExpr) ir.Node {
+ assertOp(n, ir.OINDEXMAP)
+ if hasRType(n, n.RType, "RType") {
+ return n.RType
+ }
+ return mapRType(pos, n.X.Type())
+}
+
+// MakeChanRType asserts that n is a "make" operation for a channel
+// type, and returns an expression that yields the *runtime._type
+// value representing that channel type.
+func MakeChanRType(pos src.XPos, n *ir.MakeExpr) ir.Node {
+ assertOp(n, ir.OMAKECHAN)
+ if hasRType(n, n.RType, "RType") {
+ return n.RType
+ }
+ return chanRType(pos, n.Type())
+}
+
+// MakeMapRType asserts that n is a "make" operation for a map type,
+// and returns an expression that yields the *runtime._type value
+// representing that map type.
+func MakeMapRType(pos src.XPos, n *ir.MakeExpr) ir.Node {
+ assertOp(n, ir.OMAKEMAP)
+ if hasRType(n, n.RType, "RType") {
+ return n.RType
+ }
+ return mapRType(pos, n.Type())
+}
+
+// MakeSliceElemRType asserts that n is a "make" operation for a slice
+// type, and returns an expression that yields the *runtime._type
+// value representing that slice type's element type.
+func MakeSliceElemRType(pos src.XPos, n *ir.MakeExpr) ir.Node {
+ assertOp2(n, ir.OMAKESLICE, ir.OMAKESLICECOPY)
+ if hasRType(n, n.RType, "RType") {
+ return n.RType
+ }
+ return sliceElemRType(pos, n.Type())
+}
+
+// RangeMapRType asserts that n is a "range" loop over a map value,
+// and returns an expression that yields the *runtime._type value
+// representing that map type.
+func RangeMapRType(pos src.XPos, n *ir.RangeStmt) ir.Node {
+ assertOp(n, ir.ORANGE)
+ if hasRType(n, n.RType, "RType") {
+ return n.RType
+ }
+ return mapRType(pos, n.X.Type())
+}
+
+// UnsafeSliceElemRType asserts that n is an "unsafe.Slice" operation,
+// and returns an expression that yields the *runtime._type value
+// representing the result slice type's element type.
+func UnsafeSliceElemRType(pos src.XPos, n *ir.BinaryExpr) ir.Node {
+ assertOp(n, ir.OUNSAFESLICE)
+ if hasRType(n, n.RType, "RType") {
+ return n.RType
+ }
+ return sliceElemRType(pos, n.Type())
+}