compiler,reflect: support channel directions
Этот коммит содержится в:
родитель
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 {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче