// 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 } 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, 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 { assertOp(n, ir.OCONVIFACE) 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()) }