Commit a0f742d3 authored by Rob Pike's avatar Rob Pike

more gob bugs

1) need to send slice and array types (was only sending element types)
2) compatibleType needs to use decoder's type map

R=rsc
CC=golang-dev
https://golang.org/cl/164062
parent 749da968
...@@ -527,7 +527,12 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp ...@@ -527,7 +527,12 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp
op = decUint8Array; op = decUint8Array;
break; break;
} }
elemId := wireId.gobType().(*sliceType).Elem; var elemId typeId;
if tt, ok := builtinIdToType[wireId]; ok {
elemId = tt.(*sliceType).Elem
} else {
elemId = dec.wireType[wireId].slice.Elem
}
elemOp, elemIndir, err := dec.decOpFor(elemId, t.Elem(), name); elemOp, elemIndir, err := dec.decOpFor(elemId, t.Elem(), name);
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
...@@ -614,7 +619,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) (decOp, os.Error) { ...@@ -614,7 +619,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) (decOp, os.Error) {
// Are these two gob Types compatible? // Are these two gob Types compatible?
// Answers the question for basic types, arrays, and slices. // Answers the question for basic types, arrays, and slices.
// Structs are considered ok; fields will be checked later. // Structs are considered ok; fields will be checked later.
func compatibleType(fr reflect.Type, fw typeId) bool { func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
for { for {
if pt, ok := fr.(*reflect.PtrType); ok { if pt, ok := fr.(*reflect.PtrType); ok {
fr = pt.Elem(); fr = pt.Elem();
...@@ -660,16 +665,22 @@ func compatibleType(fr reflect.Type, fw typeId) bool { ...@@ -660,16 +665,22 @@ func compatibleType(fr reflect.Type, fw typeId) bool {
return fw == tString return fw == tString
case *reflect.ArrayType: case *reflect.ArrayType:
aw, ok := fw.gobType().(*arrayType); aw, ok := fw.gobType().(*arrayType);
return ok && t.Len() == aw.Len && compatibleType(t.Elem(), aw.Elem); return ok && t.Len() == aw.Len && dec.compatibleType(t.Elem(), aw.Elem);
case *reflect.SliceType: case *reflect.SliceType:
// Is it an array of bytes? // Is it an array of bytes?
et := t.Elem(); et := t.Elem();
if _, ok := et.(*reflect.Uint8Type); ok { if _, ok := et.(*reflect.Uint8Type); ok {
return fw == tBytes return fw == tBytes
} }
sw, ok := fw.gobType().(*sliceType); // Extract and compare element types.
var sw *sliceType;
if tt, ok := builtinIdToType[fw]; ok {
sw = tt.(*sliceType)
} else {
sw = dec.wireType[fw].slice
}
elem, _ := indirect(t.Elem()); elem, _ := indirect(t.Elem());
return ok && compatibleType(elem, sw.Elem); return sw != nil && dec.compatibleType(elem, sw.Elem);
case *reflect.StructType: case *reflect.StructType:
return true return true
} }
...@@ -687,7 +698,7 @@ func (dec *Decoder) compileDec(remoteId typeId, rt reflect.Type) (engine *decEng ...@@ -687,7 +698,7 @@ func (dec *Decoder) compileDec(remoteId typeId, rt reflect.Type) (engine *decEng
if !ok1 || !ok2 { if !ok1 || !ok2 {
return nil, errNotStruct return nil, errNotStruct
} }
wireStruct = w.s; wireStruct = w.strct;
} }
engine = new(decEngine); engine = new(decEngine);
engine.instr = make([]decInstr, len(wireStruct.field)); engine.instr = make([]decInstr, len(wireStruct.field));
...@@ -706,7 +717,7 @@ func (dec *Decoder) compileDec(remoteId typeId, rt reflect.Type) (engine *decEng ...@@ -706,7 +717,7 @@ func (dec *Decoder) compileDec(remoteId typeId, rt reflect.Type) (engine *decEng
engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0, ovfl}; engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0, ovfl};
continue; continue;
} }
if !compatibleType(localField.Type, wireField.id) { if !dec.compatibleType(localField.Type, wireField.id) {
details := " (" + wireField.id.String() + " incompatible with " + localField.Type.String() + ") in type " + remoteId.Name(); details := " (" + wireField.id.String() + " incompatible with " + localField.Type.String() + ") in type " + remoteId.Name();
return nil, os.ErrorString("gob: wrong type for field " + wireField.name + details); return nil, os.ErrorString("gob: wrong type for field " + wireField.name + details);
} }
......
...@@ -244,17 +244,20 @@ func (enc *Encoder) sendType(origt reflect.Type) { ...@@ -244,17 +244,20 @@ func (enc *Encoder) sendType(origt reflect.Type) {
default: default:
// Basic types do not need to be described. // Basic types do not need to be described.
return return
case reflect.ArrayOrSliceType:
// If it's []uint8, don't send; it's considered basic.
if _, ok := rt.Elem().(*reflect.Uint8Type); ok {
return
}
// Otherwise we do send.
break;
// Struct types are not sent, only their element types.
case *reflect.StructType: case *reflect.StructType:
// Structs do need to be described.
break break
case *reflect.ChanType, *reflect.FuncType, *reflect.MapType, *reflect.InterfaceType: case *reflect.ChanType, *reflect.FuncType, *reflect.MapType, *reflect.InterfaceType:
// Probably a bad field in a struct. // Probably a bad field in a struct.
enc.badType(rt); enc.badType(rt);
return; return;
// Array and slice types are not sent, only their element types.
case reflect.ArrayOrSliceType:
enc.sendType(rt.Elem());
return;
} }
// Have we already sent this type? This time we ask about the base type. // Have we already sent this type? This time we ask about the base type.
...@@ -282,9 +285,13 @@ func (enc *Encoder) sendType(origt reflect.Type) { ...@@ -282,9 +285,13 @@ func (enc *Encoder) sendType(origt reflect.Type) {
// Remember we've sent the top-level, possibly indirect type too. // Remember we've sent the top-level, possibly indirect type too.
enc.sent[origt] = info.id; enc.sent[origt] = info.id;
// Now send the inner types // Now send the inner types
st := rt.(*reflect.StructType); switch st := rt.(type) {
for i := 0; i < st.NumField(); i++ { case *reflect.StructType:
enc.sendType(st.Field(i).Type) for i := 0; i < st.NumField(); i++ {
enc.sendType(st.Field(i).Type)
}
case reflect.ArrayOrSliceType:
enc.sendType(st.Elem())
} }
return; return;
} }
......
...@@ -213,3 +213,15 @@ func TestTypeToPtrPtrPtrPtrType(t *testing.T) { ...@@ -213,3 +213,15 @@ func TestTypeToPtrPtrPtrPtrType(t *testing.T) {
t.Errorf("wrong value after decode: %g not %g", ****(****t2pppp).a, ****t2.a) t.Errorf("wrong value after decode: %g not %g", ****(****t2pppp).a, ****t2.a)
} }
} }
func TestSlice(t *testing.T) {
// Encode a *T, decode a T
type Type3 struct {
a []string;
}
t3p := &Type3{[]string{"hello", "world"}};
var t3 Type3;
if err := encAndDec(t3, t3p); err != nil {
t.Error(err)
}
}
...@@ -98,13 +98,13 @@ var tBytes = bootstrapType("bytes", make([]byte, 0), 5) ...@@ -98,13 +98,13 @@ var tBytes = bootstrapType("bytes", make([]byte, 0), 5)
var tString = bootstrapType("string", "", 6) var tString = bootstrapType("string", "", 6)
// Predefined because it's needed by the Decoder // Predefined because it's needed by the Decoder
var tWireType = getTypeInfoNoError(reflect.Typeof(wireType{})).id var tWireType = mustGetTypeInfo(reflect.Typeof(wireType{})).id
func init() { func init() {
checkId(7, tWireType); checkId(7, tWireType);
checkId(8, getTypeInfoNoError(reflect.Typeof(structType{})).id); checkId(9, mustGetTypeInfo(reflect.Typeof(commonType{})).id);
checkId(9, getTypeInfoNoError(reflect.Typeof(commonType{})).id); checkId(11, mustGetTypeInfo(reflect.Typeof(structType{})).id);
checkId(10, getTypeInfoNoError(reflect.Typeof(fieldType{})).id); checkId(12, mustGetTypeInfo(reflect.Typeof(fieldType{})).id);
builtinIdToType = make(map[typeId]gobType); builtinIdToType = make(map[typeId]gobType);
for k, v := range idToType { for k, v := range idToType {
builtinIdToType[k] = v builtinIdToType[k] = v
...@@ -346,12 +346,16 @@ func bootstrapType(name string, e interface{}, expect typeId) typeId { ...@@ -346,12 +346,16 @@ func bootstrapType(name string, e interface{}, expect typeId) typeId {
// are built in encode.go's init() function. // are built in encode.go's init() function.
type wireType struct { type wireType struct {
s *structType; array *arrayType;
slice *sliceType;
strct *structType;
} }
func (w *wireType) name() string { func (w *wireType) name() string {
// generalize once we can have non-struct types on the wire. if w.strct != nil {
return w.s.name return w.strct.name
}
return "unknown";
} }
type typeInfo struct { type typeInfo struct {
...@@ -377,15 +381,25 @@ func getTypeInfo(rt reflect.Type) (*typeInfo, os.Error) { ...@@ -377,15 +381,25 @@ func getTypeInfo(rt reflect.Type) (*typeInfo, os.Error) {
return nil, err return nil, err
} }
info.id = gt.id(); info.id = gt.id();
// assume it's a struct type t := info.id.gobType();
info.wire = &wireType{info.id.gobType().(*structType)}; switch typ := rt.(type) {
case *reflect.ArrayType:
info.wire = &wireType{array: t.(*arrayType)}
case *reflect.SliceType:
// []byte == []uint8 is a special case handled separately
if _, ok := typ.Elem().(*reflect.Uint8Type); !ok {
info.wire = &wireType{slice: t.(*sliceType)}
}
case *reflect.StructType:
info.wire = &wireType{strct: t.(*structType)}
}
typeInfoMap[rt] = info; typeInfoMap[rt] = info;
} }
return info, nil; return info, nil;
} }
// Called only when a panic is acceptable and unexpected. // Called only when a panic is acceptable and unexpected.
func getTypeInfoNoError(rt reflect.Type) *typeInfo { func mustGetTypeInfo(rt reflect.Type) *typeInfo {
t, err := getTypeInfo(rt); t, err := getTypeInfo(rt);
if err != nil { if err != nil {
panicln("getTypeInfo:", err.String()) panicln("getTypeInfo:", err.String())
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment