diff --git a/src/pkg/encoding/gob/encoder.go b/src/pkg/encoding/gob/encoder.go index 284decedead..f669c3d5b24 100644 --- a/src/pkg/encoding/gob/encoder.go +++ b/src/pkg/encoding/gob/encoder.go @@ -137,8 +137,8 @@ func (enc *Encoder) sendType(w io.Writer, state *encoderState, origt reflect.Typ ut := userType(origt) if ut.isGobEncoder { // The rules are different: regardless of the underlying type's representation, - // we need to tell the other side that this exact type is a GobEncoder. - return enc.sendActualType(w, state, ut, ut.user) + // we need to tell the other side that the base type is a GobEncoder. + return enc.sendActualType(w, state, ut, ut.base) } // It's a concrete value, so drill down to the base type. diff --git a/src/pkg/encoding/gob/gobencdec_test.go b/src/pkg/encoding/gob/gobencdec_test.go index 45240d764dc..58136d3655c 100644 --- a/src/pkg/encoding/gob/gobencdec_test.go +++ b/src/pkg/encoding/gob/gobencdec_test.go @@ -142,6 +142,18 @@ type GobTest5 struct { V *ValueGobber } +type GobTest6 struct { + X int // guarantee we have something in common with GobTest* + V ValueGobber + W *ValueGobber +} + +type GobTest7 struct { + X int // guarantee we have something in common with GobTest* + V *ValueGobber + W ValueGobber +} + type GobTestIgnoreEncoder struct { X int // guarantee we have something in common with GobTest* } @@ -360,6 +372,61 @@ func TestGobEncoderValueEncoder(t *testing.T) { } } +// Test that we can use a value then a pointer type of a GobEncoder +// in the same encoded value. Bug 4647. +func TestGobEncoderValueThenPointer(t *testing.T) { + v := ValueGobber("forty-two") + w := ValueGobber("six-by-nine") + + // this was a bug: encoding a GobEncoder by value before a GobEncoder + // pointer would cause duplicate type definitions to be sent. + + b := new(bytes.Buffer) + enc := NewEncoder(b) + if err := enc.Encode(GobTest6{42, v, &w}); err != nil { + t.Fatal("encode error:", err) + } + dec := NewDecoder(b) + x := new(GobTest6) + if err := dec.Decode(x); err != nil { + t.Fatal("decode error:", err) + } + if got, want := x.V, v; got != want { + t.Errorf("v = %q, want %q", got, want) + } + if got, want := v.W, w; got == nil { + t.Errorf("w = nil, want %q", want) + } else if *got != want { + t.Errorf("w = %q, want %q", *got, want) + } +} + +// Test that we can use a pointer then a value type of a GobEncoder +// in the same encoded value. +func TestGobEncoderPointerThenValue(t *testing.T) { + v := ValueGobber("forty-two") + w := ValueGobber("six-by-nine") + + b := new(bytes.Buffer) + enc := NewEncoder(b) + if err := enc.Encode(GobTest7{42, &v, w}); err != nil { + t.Fatal("encode error:", err) + } + dec := NewDecoder(b) + x := new(GobTest7) + if err := dec.Decode(x); err != nil { + t.Fatal("decode error:", err) + } + if got, want := x.V, v; got == nil { + t.Errorf("v = nil, want %q", want) + } else if *got != want { + t.Errorf("v = %q, want %q", got, want) + } + if got, want := v.W, w; got != want { + t.Errorf("w = %q, want %q", got, want) + } +} + func TestGobEncoderFieldTypeError(t *testing.T) { // GobEncoder to non-decoder: error b := new(bytes.Buffer)