Subject: Re: bug#31742: 26.1.50; excorporate.elc byte-compiled in Emacs 25.x fails in Emacs 26.1

From: Thomas Fitzsimmons <[email-masked]>
Date: Fri, 08 Jun 2018 22:54:17 -0400

Alex Harsanyi <[email-masked]> writes:

> On Fri, Jun 8, 2018 at 10:18 PM, Thomas Fitzsimmons <[email-masked]> wrote:
>> (CCing Alex Harsanyi.)
>>
>> Noam Postavsky <[email-masked]> writes:
>>
>>> Thomas Fitzsimmons <[email-masked]> writes:
>>>
>>>> Noam Postavsky <[email-masked]> writes:
>>>>
>>>>> Thomas Fitzsimmons <[email-masked]> writes:
>>>>>
>>>>>> (defun soap-resolve-references (element wsdl)
>>>>>
>>>>>>   (let ((resolver (get (aref element 0) 'soap-resolve-references)))
>>>>>
>>>>> Ah, then it should work to replace the (aref element 0) with (type-of
>>>>> element) as long as cl-old-struct-compat-mode is enabled.
>>>>
>>>> Yes, I retested with that change and it does work.  I guess I should
>>>> submit a patch to change all those occurrences in soap-client.
>>>
>>> I just noticed soap-client is also an ELPA package; then there is the
>>> additional complication that type-of will give the wrong answer in Emacs
>>> versions 25 and older.  So you would need something like
>>>
>>>     (let ((type (type-of element)))
>>>       (if (eq type 'vector)
>>>           (aref element 0) ; For Emacs 25 and earlier.
>>>         type))
>>
>> OK, I had that on my list to investigate before patching soap-client,
>> the compatibility range of type-of, but you've done it for me, thanks.
>> A soap-type-of compatibility function probably makes sense to replace
>> the (aref ... 0) occurrences in soap-client and soap-inspect.
>>
>>>> I'm hoping cl-old-struct-compat-mode will continue to be enabled by
>>>> default for a long time.
>>>
>
> The `(aref element 0)` trick is the only one that `soap-client` uses.  All
> other struct usage is via accessor functions, the rest of the code does not
> assume they are vectors.  It seems to me that `cl-old-struct-compat-mode` is
> not needed.

OK.

> Thomas, will you prepare the patch for soap-client?

How about the attached?  I tested it in 26.1 with 25.1 excorporate.elc
byte-code, as well as with our test suite against 24.1, 25.1 and 26.1,
so it should be OK for GNU ELPA as well.

If this looks OK, I'll bump the soap-client.el version to 3.1.4 when I
push.

Thomas

>From 1638f42e494334696c3d3dc87c25af664086acaf Mon Sep 17 00:00:00 2001
From: Thomas Fitzsimmons <[email-masked]>
Date: Fri, 8 Jun 2018 22:41:28 -0400
Subject: [PATCH] soap-client: Add byte-code compatibility function

* lisp/net/soap-client.el (soap-type-of): New function.
(soap-resolve-references, soap-decode-type)
(soap-encode-attributes, soap-encode-value): Replace aref
calls with calls to soap-type-of.
* lisp/net/soap-inspect.el (soap-sample-value, soap-inspect):
Replace aref calls with calls to soap-type-of.

Co-authored-by: Noam Postavsky <[email-masked]>
---
 lisp/net/soap-client.el  | 44 ++++++++++++++++++++++++++------------------
 lisp/net/soap-inspect.el | 44 ++++++++++++++++++++++----------------------
 2 files changed, 48 insertions(+), 40 deletions(-)

diff --git a/lisp/net/soap-client.el b/lisp/net/soap-client.el
index 3996da0..2535c34 100644
--- a/lisp/net/soap-client.el
+++ b/lisp/net/soap-client.el
@@ -685,8 +685,15 @@ soap-decode-xs-basic-type
         (anyType (soap-decode-any-type node))
         (Array (soap-decode-array node))))))
 
+(defun soap-type-of (element)
+  "Return the type of ELEMENT."
+  (let ((type (type-of element)))
+    (if (eq type 'vector)
+        (aref element 0) ; For Emacs 25 and earlier.
+      type)))
+
 ;; Register methods for `soap-xs-basic-type'
-(let ((tag (aref (make-soap-xs-basic-type) 0)))
+(let ((tag (soap-type-of (make-soap-xs-basic-type))))
   (put tag 'soap-attribute-encoder #'soap-encode-xs-basic-type-attributes)
   (put tag 'soap-encoder #'soap-encode-xs-basic-type)
   (put tag 'soap-decoder #'soap-decode-xs-basic-type))
@@ -915,7 +922,7 @@ soap-decode-xs-element
     (soap-decode-type type node)))
 
 ;; Register methods for `soap-xs-element'
-(let ((tag (aref (make-soap-xs-element) 0)))
+(let ((tag (soap-type-of (make-soap-xs-element))))
   (put tag 'soap-resolve-references #'soap-resolve-references-for-xs-element)
   (put tag 'soap-attribute-encoder #'soap-encode-xs-element-attributes)
   (put tag 'soap-encoder #'soap-encode-xs-element)
@@ -1011,7 +1018,7 @@ soap-resolve-references-for-xs-attribute
       (setf (soap-xs-attribute-reference attribute)
             (soap-wsdl-get reference wsdl predicate)))))
 
-(put (aref (make-soap-xs-attribute) 0)
+(put (soap-type-of (make-soap-xs-attribute))
      'soap-resolve-references #'soap-resolve-references-for-xs-attribute)
 
 (defun soap-resolve-references-for-xs-attribute-group (attribute-group wsdl)
@@ -1036,7 +1043,7 @@ soap-resolve-references-for-xs-attribute-group
         (setf (soap-xs-attribute-group-attribute-groups attribute-group)
               (soap-xs-attribute-group-attribute-groups resolved))))))
 
-(put (aref (make-soap-xs-attribute-group) 0)
+(put (soap-type-of (make-soap-xs-attribute-group))
      'soap-resolve-references #'soap-resolve-references-for-xs-attribute-group)
 
 ;;;;; soap-xs-simple-type
@@ -1374,7 +1381,7 @@ soap-decode-xs-simple-type
       (soap-validate-xs-simple-type value type))))
 
 ;; Register methods for `soap-xs-simple-type'
-(let ((tag (aref (make-soap-xs-simple-type) 0)))
+(let ((tag (soap-type-of (make-soap-xs-simple-type))))
   (put tag 'soap-resolve-references
        #'soap-resolve-references-for-xs-simple-type)
   (put tag 'soap-attribute-encoder #'soap-encode-xs-simple-type-attributes)
@@ -1927,7 +1934,7 @@ soap-decode-xs-complex-type
             (soap-xs-complex-type-indicator type)))))
 
 ;; Register methods for `soap-xs-complex-type'
-(let ((tag (aref (make-soap-xs-complex-type) 0)))
+(let ((tag (soap-type-of (make-soap-xs-complex-type))))
   (put tag 'soap-resolve-references
        #'soap-resolve-references-for-xs-complex-type)
   (put tag 'soap-attribute-encoder #'soap-encode-xs-complex-type-attributes)
@@ -2147,7 +2154,7 @@ soap-resolve-references
 function depending on the type of the ELEMENT.
 
 If ELEMENT has no resolver function, it is silently ignored."
-  (let ((resolver (get (aref element 0) 'soap-resolve-references)))
+  (let ((resolver (get (soap-type-of element) 'soap-resolve-references)))
     (when resolver
       (funcall resolver element wsdl))))
 
@@ -2272,13 +2279,13 @@ soap-resolve-references-for-port
 
 ;; Install resolvers for our types
 (progn
-  (put (aref (make-soap-message) 0) 'soap-resolve-references
+  (put (soap-type-of (make-soap-message)) 'soap-resolve-references
        'soap-resolve-references-for-message)
-  (put (aref (make-soap-operation) 0) 'soap-resolve-references
+  (put (soap-type-of (make-soap-operation)) 'soap-resolve-references
        'soap-resolve-references-for-operation)
-  (put (aref (make-soap-binding) 0) 'soap-resolve-references
+  (put (soap-type-of (make-soap-binding)) 'soap-resolve-references
        'soap-resolve-references-for-binding)
-  (put (aref (make-soap-port) 0) 'soap-resolve-references
+  (put (soap-type-of (make-soap-port)) 'soap-resolve-references
        'soap-resolve-references-for-port))
 
 (defun soap-wsdl-resolve-references (wsdl)
@@ -2685,16 +2692,17 @@ soap-decode-type
                (cond ((listp type)
                       (catch 'done
                         (dolist (union-member type)
-                          (let* ((decoder (get (aref union-member 0)
+                          (let* ((decoder (get (soap-type-of union-member)
                                                'soap-decoder))
                                  (result (ignore-errors
                                            (funcall decoder
                                                     union-member node))))
                             (when result (throw 'done result))))))
                      (t
-                      (let ((decoder (get (aref type 0) 'soap-decoder)))
+                      (let ((decoder (get (soap-type-of type) 'soap-decoder)))
                         (cl-assert decoder nil
-                                   "no soap-decoder for %s type" (aref type 0))
+                                   "no soap-decoder for %s type"
+                                   (soap-type-of type))
                         (funcall decoder type node))))))))))
 
 (defun soap-decode-any-type (node)
@@ -2878,9 +2886,9 @@ soap-encode-attributes
 
 Attributes are inserted in the current buffer at the current
 position."
-  (let ((attribute-encoder (get (aref type 0) 'soap-attribute-encoder)))
+  (let ((attribute-encoder (get (soap-type-of type) 'soap-attribute-encoder)))
     (cl-assert attribute-encoder nil
-               "no soap-attribute-encoder for %s type" (aref type 0))
+               "no soap-attribute-encoder for %s type" (soap-type-of type))
     (funcall attribute-encoder value type)))
 
 (defun soap-encode-value (value type)
@@ -2892,8 +2900,8 @@ soap-encode-value
 is to be encoded.  This is a generic function which finds an
 encoder function based on TYPE and calls that encoder to do the
 work."
-  (let ((encoder (get (aref type 0) 'soap-encoder)))
-    (cl-assert encoder nil "no soap-encoder for %s type" (aref type 0))
+  (let ((encoder (get (soap-type-of type) 'soap-encoder)))
+    (cl-assert encoder nil "no soap-encoder for %s type" (soap-type-of type))
     (funcall encoder value type))
   (when (soap-element-namespace-tag type)
     (add-to-list 'soap-encoded-namespaces (soap-element-namespace-tag type))))
diff --git a/lisp/net/soap-inspect.el b/lisp/net/soap-inspect.el
index 050be45..252b1f3 100644
--- a/lisp/net/soap-inspect.el
+++ b/lisp/net/soap-inspect.el
@@ -49,10 +49,10 @@ soap-sample-value
 
 This is a generic function, depending on TYPE a specific function
 will be called."
-  (let ((sample-value (get (aref type 0) 'soap-sample-value)))
+  (let ((sample-value (get (soap-type-of type) 'soap-sample-value)))
     (if sample-value
         (funcall sample-value type)
-      (error "Cannot provide sample value for type %s" (aref type 0)))))
+      (error "Cannot provide sample value for type %s" (soap-type-of type)))))
 
 (defun soap-sample-value-for-xs-basic-type (type)
   "Provide a sample value for TYPE, an xs-basic-type.
@@ -174,31 +174,31 @@ soap-sample-value-for-message
 
 (progn
   ;; Install soap-sample-value methods for our types
-  (put (aref (make-soap-xs-basic-type) 0)
+  (put (soap-type-of (make-soap-xs-basic-type))
        'soap-sample-value
        'soap-sample-value-for-xs-basic-type)
 
-  (put (aref (make-soap-xs-element) 0)
+  (put (soap-type-of (make-soap-xs-element))
        'soap-sample-value
        'soap-sample-value-for-xs-element)
 
-  (put (aref (make-soap-xs-attribute) 0)
+  (put (soap-type-of (make-soap-xs-attribute))
        'soap-sample-value
        'soap-sample-value-for-xs-attribute)
 
-  (put (aref (make-soap-xs-attribute) 0)
+  (put (soap-type-of (make-soap-xs-attribute))
        'soap-sample-value
        'soap-sample-value-for-xs-attribute-group)
 
-  (put (aref (make-soap-xs-simple-type) 0)
+  (put (soap-type-of (make-soap-xs-simple-type))
        'soap-sample-value
        'soap-sample-value-for-xs-simple-type)
 
-  (put (aref (make-soap-xs-complex-type) 0)
+  (put (soap-type-of (make-soap-xs-complex-type))
        'soap-sample-value
        'soap-sample-value-for-xs-complex-type)
 
-  (put (aref (make-soap-message) 0)
+  (put (soap-type-of (make-soap-message))
        'soap-sample-value
        'soap-sample-value-for-message))
 
@@ -222,7 +222,7 @@ soap-inspect
 The buffer is populated with information about ELEMENT with links
 to its sub elements.  If ELEMENT is the WSDL document itself, the
 entire WSDL can be inspected."
-  (let ((inspect (get (aref element 0) 'soap-inspect)))
+  (let ((inspect (get (soap-type-of element) 'soap-inspect)))
     (unless inspect
       (error "Soap-inspect: no inspector for element"))
 
@@ -507,39 +507,39 @@ soap-inspect-wsdl
 (progn
   ;; Install the soap-inspect methods for our types
 
-  (put (aref (make-soap-xs-basic-type) 0) 'soap-inspect
+  (put (soap-type-of (make-soap-xs-basic-type)) 'soap-inspect
        'soap-inspect-xs-basic-type)
 
-  (put (aref (make-soap-xs-element) 0) 'soap-inspect
+  (put (soap-type-of (make-soap-xs-element)) 'soap-inspect
        'soap-inspect-xs-element)
 
-  (put (aref (make-soap-xs-simple-type) 0) 'soap-inspect
+  (put (soap-type-of (make-soap-xs-simple-type)) 'soap-inspect
        'soap-inspect-xs-simple-type)
 
-  (put (aref (make-soap-xs-complex-type) 0) 'soap-inspect
+  (put (soap-type-of (make-soap-xs-complex-type)) 'soap-inspect
        'soap-inspect-xs-complex-type)
 
-  (put (aref (make-soap-xs-attribute) 0) 'soap-inspect
+  (put (soap-type-of (make-soap-xs-attribute)) 'soap-inspect
        'soap-inspect-xs-attribute)
 
-  (put (aref (make-soap-xs-attribute-group) 0) 'soap-inspect
+  (put (soap-type-of (make-soap-xs-attribute-group)) 'soap-inspect
        'soap-inspect-xs-attribute-group)
 
-  (put (aref (make-soap-message) 0) 'soap-inspect
+  (put (soap-type-of (make-soap-message)) 'soap-inspect
        'soap-inspect-message)
-  (put (aref (make-soap-operation) 0) 'soap-inspect
+  (put (soap-type-of (make-soap-operation)) 'soap-inspect
        'soap-inspect-operation)
 
-  (put (aref (make-soap-port-type) 0) 'soap-inspect
+  (put (soap-type-of (make-soap-port-type)) 'soap-inspect
        'soap-inspect-port-type)
 
-  (put (aref (make-soap-binding) 0) 'soap-inspect
+  (put (soap-type-of (make-soap-binding)) 'soap-inspect
        'soap-inspect-binding)
 
-  (put (aref (make-soap-port) 0) 'soap-inspect
+  (put (soap-type-of (make-soap-port)) 'soap-inspect
        'soap-inspect-port)
 
-  (put (aref (soap-make-wsdl "origin") 0) 'soap-inspect
+  (put (soap-type-of (soap-make-wsdl "origin")) 'soap-inspect
        'soap-inspect-wsdl))
 
 (provide 'soap-inspect)
-- 
1.8.3.1