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