compiler,reflect: support channel directions

Этот коммит содержится в:
Damian Gryski 2023-03-24 09:35:16 -07:00 коммит произвёл Ron Evans
родитель 1213a45197
коммит 3fbd3c4d93
2 изменённых файлов: 65 добавлений и 8 удалений

Просмотреть файл

@ -60,6 +60,14 @@ const (
structFieldFlagIsEmbedded structFieldFlagIsEmbedded
) )
type reflectChanDir int
const (
refRecvDir reflectChanDir = 1 << iota // <-chan
refSendDir // chan<-
refBothDir = refRecvDir | refSendDir // chan
)
// createMakeInterface emits the LLVM IR for the *ssa.MakeInterface instruction. // createMakeInterface emits the LLVM IR for the *ssa.MakeInterface instruction.
// It tries to put the type in the interface value, but if that's not possible, // It tries to put the type in the interface value, but if that's not possible,
// it will do an allocation of the right size and put that in the interface // it will do an allocation of the right size and put that in the interface
@ -161,7 +169,13 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
types.NewVar(token.NoPos, nil, "pkgpath", types.Typ[types.UnsafePointer]), types.NewVar(token.NoPos, nil, "pkgpath", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "name", types.NewArray(types.Typ[types.Int8], int64(len(pkgname)+1+len(name)+1))), types.NewVar(token.NoPos, nil, "name", types.NewArray(types.Typ[types.Int8], int64(len(pkgname)+1+len(name)+1))),
) )
case *types.Chan, *types.Slice: case *types.Chan:
typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]), // reuse for select chan direction
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
)
case *types.Slice:
typeFieldTypes = append(typeFieldTypes, typeFieldTypes = append(typeFieldTypes,
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]), types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]), types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
@ -243,10 +257,20 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
} }
metabyte |= 1 << 5 // "named" flag metabyte |= 1 << 5 // "named" flag
case *types.Chan: case *types.Chan:
var dir reflectChanDir
switch typ.Dir() {
case types.SendRecv:
dir = refBothDir
case types.RecvOnly:
dir = refRecvDir
case types.SendOnly:
dir = refSendDir
}
typeFields = []llvm.Value{ typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods llvm.ConstInt(c.ctx.Int16Type(), uint64(dir), false), // actually channel direction
c.getTypeCode(types.NewPointer(typ)), // ptrTo c.getTypeCode(types.NewPointer(typ)), // ptrTo
c.getTypeCode(typ.Elem()), // elementType c.getTypeCode(typ.Elem()), // elementType
} }
case *types.Slice: case *types.Slice:
typeFields = []llvm.Value{ typeFields = []llvm.Value{
@ -448,7 +472,17 @@ func getTypeCodeName(t types.Type) (string, bool) {
return "basic:" + basicTypeNames[t.Kind()], false return "basic:" + basicTypeNames[t.Kind()], false
case *types.Chan: case *types.Chan:
s, isLocal := getTypeCodeName(t.Elem()) s, isLocal := getTypeCodeName(t.Elem())
return "chan:" + s, isLocal var dir string
switch t.Dir() {
case types.SendOnly:
dir = "s:"
case types.RecvOnly:
dir = "r:"
case types.SendRecv:
dir = "sr:"
}
return "chan:" + dir + s, isLocal
case *types.Interface: case *types.Interface:
isLocal := false isLocal := false
methods := make([]string, t.NumMethods()) methods := make([]string, t.NumMethods())

Просмотреть файл

@ -517,7 +517,23 @@ func (t *rawType) String() string {
switch t.Kind() { switch t.Kind() {
case Chan: case Chan:
return "chan " + t.elem().String() elem := t.elem().String()
switch t.ChanDir() {
case SendDir:
return "chan<- " + elem
case RecvDir:
return "<-chan " + elem
case BothDir:
if elem[0] == '<' {
// typ is recv chan, need parentheses as "<-" associates with leftmost
// chan possible, see:
// * https://golang.org/ref/spec#Channel_types
// * https://github.com/golang/go/issues/39897
return "chan (" + elem + ")"
}
return "chan " + elem
}
case Pointer: case Pointer:
return "*" + t.elem().String() return "*" + t.elem().String()
case Slice: case Slice:
@ -991,8 +1007,15 @@ func (t *rawType) isBinary() bool {
return false return false
} }
func (t rawType) ChanDir() ChanDir { func (t *rawType) ChanDir() ChanDir {
panic("unimplemented: (reflect.Type).ChanDir()") if t.Kind() != Chan {
panic(TypeError{"ChanDir"})
}
dir := int((*elemType)(unsafe.Pointer(t)).numMethod)
// nummethod is overloaded for channel to store channel direction
return ChanDir(dir)
} }
func (t *rawType) ConvertibleTo(u Type) bool { func (t *rawType) ConvertibleTo(u Type) bool {