You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: discard.go
    path of file: ./repos/trickster/vendor/github.com/gogo/protobuf/proto
    
    the code of the file until where you have to start completion: // Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2017 The Go Au
    
func discardLegacy(m Message) {
	v := reflect.ValueOf(m)
	if v.Kind() != reflect.Ptr || v.IsNil() {
		return
	}
	v = v.Elem()
	if v.Kind() != reflect.Struct {
		return
	}
	t := v.Type()

	for i := 0; i < v.NumField(); i++ {
		f := t.Field(i)
		if strings.HasPrefix(f.Name, "XXX_") {
			continue
		}
		vf := v.Field(i)
		tf := f.Type

		// Unwrap tf to get its most basic type.
		var isPointer, isSlice bool
		if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 {
			isSlice = true
			tf = tf.Elem()
		}
		if tf.Kind() == reflect.Ptr {
			isPointer = true
			tf = tf.Elem()
		}
		if isPointer && isSlice && tf.Kind() != reflect.Struct {
			panic(fmt.Sprintf("%T.%s cannot be a slice of pointers to primitive types", m, f.Name))
		}

		switch tf.Kind() {
		case reflect.Struct:
			switch {
			case !isPointer:
				panic(fmt.Sprintf("%T.%s cannot be a direct struct value", m, f.Name))
			case isSlice: // E.g., []*pb.T
				for j := 0; j < vf.Len(); j++ {
					discardLegacy(vf.Index(j).Interface().(Message))
				}
			default: // E.g., *pb.T
				discardLegacy(vf.Interface().(Message))
			}
		case reflect.Map:
			switch {
			case isPointer || isSlice:
				panic(fmt.Sprintf("%T.%s cannot be a pointer to a map or a slice of map values", m, f.Name))
			default: // E.g., map[K]V
				tv := vf.Type().Elem()
				if tv.Kind() == reflect.Ptr && tv.Implements(protoMessageType) { // Proto struct (e.g., *T)
					for _, key := range vf.MapKeys() {
						val := vf.MapIndex(key)
						discardLegacy(val.Interface().(Message))
					}
				}
			}
		case reflect.Interface:
			// Must be oneof field.
			switch {
			case isPointer || isSlice:
				panic(fmt.Sprintf("%T.%s cannot be a pointer to a interface or a slice of interface values", m, f.Name))
			default: // E.g., test_proto.isCommunique_Union interface
				if !vf.IsNil() && f.Tag.Get("protobuf_oneof") != "" {
					vf = vf.Elem() // E.g., *test_proto.Communique_Msg
					if !vf.IsNil() {
						vf = vf.Elem()   // E.g., test_proto.Communique_Msg
						vf = vf.Field(0) // E.g., Proto struct (e.g., *T) or primitive value
						if vf.Kind() == reflect.Ptr {
							discardLegacy(vf.Interface().(Message))
						}
					}
				}
			}
		}
	}

	if vf := v.FieldByName("XXX_unrecognized"); vf.IsValid() {
		if vf.Type() != reflect.TypeOf([]byte{}) {
			panic("expected XXX_unrecognized to be of type []byte")
		}
		vf.Set(reflect.ValueOf([]byte(nil)))
	}

	// For proto2 messages, only discard unknown fields in message extensions
	// that have been accessed via GetExtension.
	if em, err := extendable(m); err == nil {
		// Ignore lock since discardLegacy is not concurrency safe.
		emm, _ := em.extensionsRead()
		for _, mx := range emm {
			if m, ok := mx.value.(Message); ok {
				discardLegacy(m)
			}
		}
	}
}