diff options
Diffstat (limited to 'src/cmd/compile/internal/reflectdata/helpers.go')
-rw-r--r-- | src/cmd/compile/internal/reflectdata/helpers.go | 226 |
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()) +} |