Subject: 27.0.50; [PATCH] WIP on using gnus info accessor macros

From: Eric Abrahamsen <[email-masked]>
Date: Wed, 30 Oct 2019 16:58:52 -0700

The attached patch is a work-in-progress for making sure that all of
Gnus' code only accesses group infos via the relevant macros --
essentially hiding the fact that group infos are implemented as lists,
in anticipation of eventually being able to re-implement them as structs
at some point in the future.

Essentially, "(nth 3 info)" becomes "(gnus-info-marks info)", and so
one.

It also replaces uses of "gnus-info-set-*" with "(setf (gnus-info-* ".
The setter macros aren't deprecated, though.

My main question is about the use of the EXTEND argument to
`gnus-info-set-marks', `gnus-info-set-method', and
`gnus-info-set-params'. In the current patch, I have left the setter
intact wherever the EXTEND argument is passed, until I can figure this
out.

If I could understand why _some_ of the infos are expected to be short a
few elements (newly-created groups?), I would rather provide a
`make-gnus-info' function (again, in anticipation of a struct
constructor), which could be called with the elements of an info (either
as a list or spread) and return an info filled-out with nils where
necessary. Then that could be used wherever we expect a short info.

There's also the weird spot in gnus-sum.el:6183 where we're chopping off
nil elements from the end of an info list, I don't know why.

One last bit I'm uncertain about is in `nnvirtual-request-update-info',
where I've replaced this:

      (setcar (cddr info) nnvirtual-mapping-reads)
      (if (nthcdr 3 info)
	  (setcar (nthcdr 3 info) nnvirtual-mapping-marks)
	(when nnvirtual-mapping-marks
	  (setcdr (nthcdr 2 info) (list nnvirtual-mapping-marks))))

with this:

      (setf (gnus-info-read info) nnvirtual-mapping-reads)
      (when nnvirtual-mapping-marks
	(setf (gnus-info-marks info) nnvirtual-mapping-marks))

It seems to work fine, but to be honest I don't really understand the
original logic.

Eric

>From 8e509a640b0496ae419221e45ee36c43bcc8ca94 Mon Sep 17 00:00:00 2001
From: Eric Abrahamsen <[email-masked]>
Date: Wed, 17 Jul 2019 18:49:27 -0700
Subject: [PATCH] WIP on using gnus info accessors

---
 lisp/gnus/gnus-agent.el | 36 +++++++++++-----------
 lisp/gnus/gnus-group.el | 66 ++++++++++++++++++++++-------------------
 lisp/gnus/gnus-int.el   |  2 +-
 lisp/gnus/gnus-sieve.el |  2 +-
 lisp/gnus/gnus-start.el | 64 +++++++++++++++++++--------------------
 lisp/gnus/gnus-sum.el   | 37 ++++++++++++-----------
 lisp/gnus/gnus.el       |  6 ++--
 lisp/gnus/nndiary.el    |  5 ++--
 lisp/gnus/nndraft.el    | 18 +++++------
 lisp/gnus/nnimap.el     | 20 +++++++------
 lisp/gnus/nnir.el       |  8 ++---
 lisp/gnus/nnmaildir.el  |  6 ++--
 lisp/gnus/nnmairix.el   | 38 +++++++++++-------------
 lisp/gnus/nnml.el       |  4 +--
 lisp/gnus/nnvirtual.el  | 17 +++++------
 15 files changed, 168 insertions(+), 161 deletions(-)

diff --git a/lisp/gnus/gnus-agent.el b/lisp/gnus/gnus-agent.el
index 1f25255278..a58a35df98 100644
--- a/lisp/gnus/gnus-agent.el
+++ b/lisp/gnus/gnus-agent.el
@@ -1212,22 +1212,21 @@ gnus-agent-synchronize-group-flags
 	      (marks (nth 2 action)))
 	  (dolist (mark marks)
 	    (cond ((eq mark 'read)
-		   (gnus-info-set-read
-		    info
-		    (funcall (if (eq what 'add)
-				 'gnus-range-add
-			       'gnus-remove-from-range)
-			     (gnus-info-read info)
-			     range))
+		   (setf (gnus-info-read info)
+			 (funcall (if (eq what 'add)
+				      'gnus-range-add
+				    'gnus-remove-from-range)
+				  (gnus-info-read info)
+				  range))
 		   (gnus-get-unread-articles-in-group
 		    info
 		    (gnus-active (gnus-info-group info))))
 		  ((memq mark '(tick))
 		   (let ((info-marks (assoc mark (gnus-info-marks info))))
 		     (unless info-marks
-                       (gnus-info-set-marks
-                        info (cons (setq info-marks (list mark))
-                                   (gnus-info-marks info))))
+		       (setf (gnus-info-marks info)
+			     (cons (setq info-marks (list mark))
+				   (gnus-info-marks info))))
                      (setcdr info-marks
                              (funcall (if (eq what 'add)
                                           'gnus-range-add
@@ -1303,12 +1302,11 @@ gnus-agent-possibly-alter-active
           ;; file.
 
           (let ((read (gnus-info-read info)))
-            (gnus-info-set-read
-             info
-             (gnus-range-add
-              read
-              (list (cons (1+ agent-max)
-                          (1- active-min))))))
+	    (setf (gnus-info-read info)
+		  (gnus-range-add
+		   read
+		   (list (cons (1+ agent-max)
+                               (1- active-min))))))
 
           ;; Lie about the agent's local range for this group to
           ;; disable the set read each time this server is opened.
@@ -2535,11 +2533,11 @@ gnus-agent-fetch-group-1
                           (when (cdr marked-arts)
                             (setq marks
 				  (delq marked-arts (gnus-info-marks info)))
-                            (gnus-info-set-marks info marks)))))
+			    (setf (gnus-info-marks info) marks)))))
                     (let ((read (gnus-info-read
 				 (or info (setq info (gnus-get-info group))))))
-                      (gnus-info-set-read
-		       info (gnus-add-to-range read unfetched-articles)))
+		      (setf (gnus-info-read info)
+			    (gnus-add-to-range read unfetched-articles)))
 
                     (gnus-group-update-group group t)
                     (sit-for 0)
diff --git a/lisp/gnus/gnus-group.el b/lisp/gnus/gnus-group.el
index 8f5f5d66e4..369c3c2906 100644
--- a/lisp/gnus/gnus-group.el
+++ b/lisp/gnus/gnus-group.el
@@ -1423,7 +1423,7 @@ gnus-group-update-group-line
 	   (not (gnus-ephemeral-group-p group))
 	   (gnus-dribble-enter
 	    (concat "(gnus-group-set-info '"
-		    (gnus-prin1-to-string (nth 1 entry))
+		    (gnus-prin1-to-string (gnus-get-info group))
 		    ")")
 	    (concat "^(gnus-group-set-info '(\"" (regexp-quote group) "\"")))
       (setq gnus-group-indentation (gnus-group-group-indentation))
@@ -1440,10 +1440,10 @@ gnus-group-insert-group-line-info
     (if entry
 	(progn
 	  ;; (Un)subscribed group.
-	  (setq info (nth 1 entry))
+	  (setq info (gnus-get-info group))
 	  (gnus-group-insert-group-line
 	   group (gnus-info-level info) (gnus-info-marks info)
-	   (or (car entry) t) (gnus-info-method info)))
+	   (or (gnus-group-unread group) t) (gnus-info-method info)))
       ;; This group is dead.
       (gnus-group-insert-group-line
        group
@@ -1457,7 +1457,7 @@ gnus-group-insert-group-line-info
        (gnus-method-simplify (gnus-find-method-for-group group))))))
 
 (defun gnus-number-of-unseen-articles-in-group (group)
-  (let* ((info (nth 1 (gnus-group-entry group)))
+  (let* ((info (gnus-get-info group))
 	 (marked (gnus-info-marks info))
 	 (seen (cdr (assq 'seen marked)))
 	 (active (gnus-active group)))
@@ -1595,15 +1595,15 @@ gnus-group-update-eval-form
   "Eval `car' of each element of LIST, and return the first that return t.
 Some value are bound so the form can use them."
   (when list
-    (let* ((entry (gnus-group-entry group))
+    (let* ((unread (gnus-group-unread group))
            (active (gnus-active group))
-           (info (nth 1 entry))
+           (info (gnus-get-info group))
            (method (inline (gnus-server-get-method
 			    group (gnus-info-method info))))
            (marked (gnus-info-marks info))
 	   (env
 	    (list
-	     (cons 'unread (if (numberp (car entry)) (car entry) 0))
+	     (cons 'unread (if (numberp unread) unread 0))
 	     (cons 'total (if active (1+ (- (cdr active) (car active))) 0))
 	     (cons 'mailp (apply
 			   'append
@@ -1676,7 +1676,7 @@ gnus-group-update-group
 			 (not (gnus-ephemeral-group-p group)))
 		(gnus-dribble-enter
 		 (concat "(gnus-group-set-info '"
-			 (gnus-prin1-to-string (nth 1 entry))
+			 (gnus-prin1-to-string (gnus-get-info group))
 			 ")")
 		 (concat "^(gnus-group-set-info '(\""
 			 (regexp-quote group) "\"")))))
@@ -2958,9 +2958,9 @@ gnus-group-edit-group-done
 			(if (or (not method)
 				(gnus-server-equal
 				 gnus-select-method method))
-			    (gnus-group-real-name (car info))
+			    (gnus-group-real-name group)
 			  (gnus-group-prefixed-name
-			   (gnus-group-real-name (car info)) method))
+			   (gnus-group-real-name group) method))
 		      nil)))
     (when (and new-group
 	       (not (equal new-group group)))
@@ -2973,11 +2973,11 @@ gnus-group-edit-group-done
       (setq info (copy-tree info))
       (setcar info new-group)
       (unless (gnus-server-equal method "native")
-	(unless (nthcdr 3 info)
+	(unless (gnus-info-marks info)
 	  (nconc info (list nil nil)))
-	(unless (nthcdr 4 info)
+	(unless (gnus-info-method info)
 	  (nconc info (list nil)))
-	(gnus-info-set-method info method))
+	(setf (gnus-info-method info) method))
       (gnus-group-set-info info))
     (gnus-group-update-group (or new-group group))
     (gnus-group-position-point)))
@@ -3531,17 +3531,18 @@ gnus-info-clear-data
     (gnus-undo-register
       `(progn
 	 (gnus-request-set-mark ,group ',action)
+	 ;; FIXME: Handle EXTEND.
 	 (gnus-info-set-marks ',info ',(gnus-info-marks info) t)
-	 (gnus-info-set-read ',info ',(gnus-info-read info))
+	 (setf (gnus-info-read ',info) ',(gnus-info-read info))
 	 (when (gnus-group-jump-to-group ,group)
 	   (gnus-get-unread-articles-in-group ',info ',(gnus-active group) t)
 	   (gnus-group-update-group-line))))
     (setq action (mapcar (lambda (el) (list (nth 0 el) 'del (nth 2 el)))
 			 action))
     (gnus-request-set-mark group action)
-    (gnus-info-set-read info nil)
+    (setf (gnus-info-read info) nil)
     (when (gnus-info-marks info)
-      (gnus-info-set-marks info nil))))
+      (setf (gnus-info-marks info) nil))))
 
 ;; Group catching up.
 
@@ -3903,7 +3904,7 @@ gnus-group-yank-group
     (while (>= (cl-decf arg) 0)
       (when (not (setq info (pop gnus-list-of-killed-groups)))
 	(error "No more newsgroups to yank"))
-      (push (setq group (nth 1 info)) out)
+      (push (setq group (gnus-info-group info)) out)
       ;; Find which newsgroup to insert this one before - search
       ;; backward until something suitable is found.  If there are no
       ;; other newsgroups in this buffer, just make this newsgroup the
@@ -4413,6 +4414,7 @@ gnus-group-browse-foreign-server
   (gnus-browse-foreign-server method))
 
 (defun gnus-group-set-info (info &optional method-only-group part)
+  "Update status for group represented by INFO."
   (when (or info part)
     (let* ((entry (gnus-group-entry
 		   (or method-only-group (gnus-info-group info))))
@@ -4459,11 +4461,12 @@ gnus-group-set-info
       ;; can do the update.
       (if entry
 	  (progn
-	    (setcar (nthcdr 1 entry) info)
+	    (gnus-set-info (nthcdr 1 entry) info)
 	    (when (and (not (eq (car entry) t))
 		       (gnus-active (gnus-info-group info)))
-	      (setcar entry (length
-			     (gnus-list-of-unread-articles (car info)))))
+	      (setf (gnus-group-unread (gnus-info-group info))
+		    (length
+		     (gnus-list-of-unread-articles (car info)))))
 	    ;; The above `setcar' will only affect the hashtable, not
 	    ;; the alist: update the alist separately, but only if
 	    ;; it's been initialized.
@@ -4497,20 +4500,23 @@ gnus-add-marked-articles
   (let ((info (or info (gnus-get-info group)))
 	marked m)
     (or (not info)
-	(and (not (setq marked (nthcdr 3 info)))
+	(and (not (setq marked (gnus-info-marks info)))
 	     (or (null articles)
-		 (setcdr (nthcdr 2 info)
-			 (list (list (cons type (gnus-compress-sequence
-						 articles t)))))))
-	(and (not (setq m (assq type (car marked))))
+		 ;; Group had no marks at all, set unconditionally.
+		 (setf (gnus-info-marks info)
+		       (list (cons type (gnus-compress-sequence
+					 articles t))))))
+	(and (not (setq m (assq type marked)))
 	     (or (null articles)
-		 (setcar marked
-			 (cons (cons type (gnus-compress-sequence articles t) )
-			       (car marked)))))
+		 ;; Group had no marks of TYPE.
+		 (setf (gnus-info-marks info)
+		       (cons (cons type (gnus-compress-sequence articles t))
+			     marked))))
 	(if force
+	    ;; Replace (or remove) all marks of TYPE.
 	    (if (null articles)
-		(setcar (nthcdr 3 info)
-			(assq-delete-all type (car marked)))
+		(setf (gnus-info-marks info)
+		      (assq-delete-all type marked))
 	      (setcdr m (gnus-compress-sequence articles t)))
 	  (setcdr m (gnus-compress-sequence
 		     (sort (nconc (gnus-uncompress-range (cdr m))
diff --git a/lisp/gnus/gnus-int.el b/lisp/gnus/gnus-int.el
index 0abbfe6720..a21bc25840 100644
--- a/lisp/gnus/gnus-int.el
+++ b/lisp/gnus/gnus-int.el
@@ -727,7 +727,7 @@ gnus-request-marks
 	       (let* ((range (if (= min 2) 1 (cons 1 (1- min))))
 		      (read (gnus-info-read info))
 		      (new-read (gnus-range-add read (list range))))
-		 (gnus-info-set-read info new-read)))
+		 (setf (gnus-info-read info) new-read)))
 	     info)))))
 
 (defun gnus-request-expire-articles (articles group &optional force)
diff --git a/lisp/gnus/gnus-sieve.el b/lisp/gnus/gnus-sieve.el
index fc0bf3098b..5edd6f5f7a 100644
--- a/lisp/gnus/gnus-sieve.el
+++ b/lisp/gnus/gnus-sieve.el
@@ -128,7 +128,7 @@ gnus-sieve-article-add-rule
 	  (info (gnus-get-info gnus-newsgroup-name)))
       (if (null rule)
 	  (error "Could not guess rule for article")
-	(gnus-info-set-params info (cons rule (gnus-info-params info)))
+	(push rule (gnus-info-params info))
 	(message "Added rule in group %s for article: %s" gnus-newsgroup-name
 		 rule)))))
 
diff --git a/lisp/gnus/gnus-start.el b/lisp/gnus/gnus-start.el
index e142c438ee..b8126433a4 100644
--- a/lisp/gnus/gnus-start.el
+++ b/lisp/gnus/gnus-start.el
@@ -1295,7 +1295,7 @@ gnus-group-change-level
        (t
 	(when (and (>= level gnus-level-zombie)
 		   entry)
-	  (remhash (car (nth 1 entry)) gnus-newsrc-hashtb)
+	  (remhash group gnus-newsrc-hashtb)
 	  (setq gnus-group-list (remove group gnus-group-list))
 	  (setq gnus-newsrc-alist (delq (assoc group gnus-newsrc-alist)
 					gnus-newsrc-alist)))))
@@ -1323,7 +1323,7 @@ gnus-group-change-level
 	    ;; It was alive, and it is going to stay alive, so we
 	    ;; just change the level and don't change any pointers or
 	    ;; hash table entries.
-	    (setcar (cdadr entry) level)
+	    (setf (gnus-info-level (nth 1 entry)) level)
 	  (if (listp entry)
 	      (setq info (cdr entry)
 		    num (car entry))
@@ -1577,7 +1577,7 @@ gnus-get-unread-articles-in-group
       ;; Set the number of unread articles.
       (when (and info
 		 (gnus-group-entry (gnus-info-group info)))
-	(setcar (gnus-group-entry (gnus-info-group info)) num))
+	(setf (gnus-group-unread (gnus-info-group info)) num))
       num)))
 
 ;; Go though `gnus-newsrc-alist' and compare with `gnus-active-hashtb'
@@ -1603,7 +1603,7 @@ gnus-get-unread-articles
 	 (gnus-agent-article-local-times 0)
 	 (archive-method (gnus-server-to-method "archive"))
 	 infos info group active method cmethod
-	 method-type method-group-list entry)
+	 method-type method-group-list)
     (gnus-message 6 "Checking new news...")
 
     (while newsrc
@@ -1650,8 +1650,8 @@ gnus-get-unread-articles
 	;; It leads `(gnus-group-unread group)' to return t.  See also
 	;; `gnus-group-prepare-flat'.
 	(unless active
-	  (when (setq entry (gnus-group-entry group))
-	    (setcar entry t)))))
+	  (when (gnus-group-entry group)
+	    (setf (gnus-group-unread group) t)))))
 
     ;; Sort the methods based so that the primary and secondary
     ;; methods come first.  This is done for legacy reasons to try to
@@ -1828,7 +1828,7 @@ gnus-make-hashtable-from-newsrc-alist
       ;; Make the same select-methods identical Lisp objects.
       (when (setq method (gnus-info-method info))
 	(if (setq rest (member method methods))
-	    (gnus-info-set-method info (car rest))
+	    (setf (gnus-info-method info) (car rest))
 	  (push method methods)))
       ;; Check for encoded group names and decode them.
       (when (string-match-p "[^[:ascii:]]" (setq gname (car info)))
@@ -1879,9 +1879,9 @@ gnus-parse-active
 
 (defun gnus-make-articles-unread (group articles)
   "Mark ARTICLES in GROUP as unread."
-  (let* ((info (nth 1 (or (gnus-group-entry group)
-			  (gnus-group-entry
-			   (gnus-group-real-name group)))))
+  (let* ((info (or (gnus-get-info group)
+		   (gnus-get-info
+		    (gnus-group-real-name group))))
 	 (ranges (gnus-info-read info))
 	 news article)
     (while articles
@@ -1890,8 +1890,8 @@ gnus-make-articles-unread
 	(push article news)))
     (when news
       ;; Enter this list into the group info.
-      (gnus-info-set-read
-       info (gnus-remove-from-range (gnus-info-read info) (nreverse news)))
+      (setf (gnus-info-read info)
+	    (gnus-remove-from-range (gnus-info-read info) (nreverse news)))
 
       ;; Set the number of unread articles in gnus-newsrc-hashtb.
       (gnus-get-unread-articles-in-group info (gnus-active group))
@@ -1901,9 +1901,8 @@ gnus-make-articles-unread
 
 (defun gnus-make-ascending-articles-unread (group articles)
   "Mark ascending ARTICLES in GROUP as unread."
-  (let* ((entry (or (gnus-group-entry group)
-                    (gnus-group-entry (gnus-group-real-name group))))
-         (info (nth 1 entry))
+  (let* ((info (or (gnus-get-info group)
+                   (gnus-get-info (gnus-group-real-name group))))
 	 (ranges (gnus-info-read info))
          (r ranges)
 	 modified)
@@ -1911,7 +1910,7 @@ gnus-make-ascending-articles-unread
     (while articles
       (let ((article (pop articles))) ; get the next article to remove from ranges
         (while (let ((range (car ranges))) ; note the current range
-                 (if (atom range)       ; single value range
+                 (if (atom range)	   ; single value range
                      (cond ((not range)
                             ;; the articles extend past the end of the ranges
                             ;; OK - I'm done
@@ -1958,7 +1957,7 @@ gnus-make-ascending-articles-unread
       (when (eq modified 'remove-null)
         (setq r (delq nil r)))
       ;; Enter this list into the group info.
-      (gnus-info-set-read info r)
+      (setf (gnus-info-read info) r)
 
       ;; Set the number of unread articles in gnus-newsrc-hashtb.
       (gnus-get-unread-articles-in-group info (gnus-active group))
@@ -2362,12 +2361,11 @@ gnus-convert-old-ticks
 	(setq dormant (cdr (assq 'dormant marks))
 	      ticked (cdr (assq 'tick marks)))
 	(when (or dormant ticked)
-	  (gnus-info-set-read
-	   info
-	   (gnus-add-to-range
-	    (gnus-info-read info)
-	    (nconc (gnus-uncompress-range dormant)
-		   (gnus-uncompress-range ticked)))))))))
+	  (setf (gnus-info-read info)
+		(gnus-add-to-range
+		 (gnus-info-read info)
+		 (nconc (gnus-uncompress-range dormant)
+			(gnus-uncompress-range ticked)))))))))
 
 (defun gnus-load (file)
   "Load FILE, but in such a way that read errors can be reported."
@@ -2438,9 +2436,9 @@ gnus-read-old-newsrc-el-file
       (while (setq group (pop newsrc))
 	(if (setq info (gnus-get-info (car group)))
 	    (progn
-	      (gnus-info-set-read info (cddr group))
-	      (gnus-info-set-level
-	       info (if (nth 1 group) gnus-level-default-subscribed
+	      (setf (gnus-info-read info) (cddr group))
+	      (setf (gnus-info-level info)
+		    (if (nth 1 group) gnus-level-default-subscribed
 		      gnus-level-default-unsubscribed))
 	      (push info gnus-newsrc-alist))
 	  (push (setq info
@@ -2451,10 +2449,10 @@ gnus-read-old-newsrc-el-file
 		gnus-newsrc-alist))
 	;; Copy marks into info.
 	(when (setq m (assoc (car group) marked))
-	  (unless (nthcdr 3 info)
+	  (unless (gnus-info-marks info)
 	    (nconc info (list nil)))
-	  (gnus-info-set-marks
-	   info (list (cons 'tick (gnus-compress-sequence
+	  (setf (gnus-info-marks info)
+		(list (cons 'tick (gnus-compress-sequence
 				   (sort (cdr m) '<) t))))))
       (setq newsrc killed)
       (while newsrc
@@ -2609,7 +2607,7 @@ gnus-newsrc-to-gnus-format
 		;; There is an entry for this file in
 		;; `gnus-newsrc-hashtb'.
 		(progn
-		  (gnus-info-set-read info (nreverse reads))
+		  (setf (gnus-info-read info) (nreverse reads))
 		  ;; We update the level very gently.  In fact, we
 		  ;; only change it if there's been a status change
 		  ;; from subscribed to unsubscribed, or vice versa.
@@ -2621,7 +2619,7 @@ gnus-newsrc-to-gnus-format
 				       (1+ gnus-level-default-unsubscribed))))
 			((and (> level gnus-level-subscribed) subscribed)
 			 (setq level gnus-level-default-subscribed)))
-		  (gnus-info-set-level info level))
+		  (setf (gnus-info-level info) level))
 	      ;; This is a new group.
 	      (setq info (list group
 			       (if subscribed
@@ -2645,7 +2643,7 @@ gnus-newsrc-to-gnus-format
 	    (prev gnus-newsrc-alist)
 	    entry mentry)
 	(while rc
-	  (or (null (nth 4 (car rc)))	; It's a native group.
+	  (or (null (gnus-info-method (car rc))) ; It's a native group.
 	      (assoc (caar rc) newsrc)	; It's already in the alist.
 	      (if (setq entry (assoc (caar prev) newsrc))
 		  (setcdr (setq mentry (memq entry newsrc))
@@ -2952,7 +2950,7 @@ gnus-gnus-to-newsrc-format
 	(insert gnus-newsrc-options))
       ;; Write subscribed and unsubscribed.
       (dolist (g-name groups)
-	(setq info (nth 1 (gnus-group-entry g-name)))
+	(setq info (gnus-get-info g-name))
 	;; Maybe don't write foreign groups to .newsrc.
 	(when (or (null (setq method (gnus-info-method info)))
 		  (equal method "native")
diff --git a/lisp/gnus/gnus-sum.el b/lisp/gnus/gnus-sum.el
index f21bc7584e..b235df8439 100644
--- a/lisp/gnus/gnus-sum.el
+++ b/lisp/gnus/gnus-sum.el
@@ -6178,6 +6178,7 @@ gnus-update-marks
 	(when newmarked
 	  (setcdr (nthcdr 2 info) (list newmarked))))
 
+      ;; FIXME: Why is this necessary?
       ;; Cut off the end of the info if there's nothing else there.
       (let ((i 5))
 	(while (and (> i 2)
@@ -6278,7 +6279,7 @@ gnus-create-xref-hashtb
 (defun gnus-mark-xrefs-as-read (from-newsgroup headers unreads)
   "Look through all the headers and mark the Xrefs as read."
   (let ((virtual (gnus-virtual-group-p from-newsgroup))
-	info xref-hashtb method nth4)
+	info xref-hashtb method tmp-method)
     (with-current-buffer gnus-group-buffer
       (when (setq xref-hashtb
 		  (gnus-create-xref-hashtb from-newsgroup headers unreads))
@@ -6288,17 +6289,18 @@ gnus-mark-xrefs-as-read
 	     ;; Dead groups are not updated.
 	     (and (prog1
 		      (setq info (gnus-get-info group))
-		    (when (stringp (setq nth4 (gnus-info-method info)))
-		      (setq nth4 (gnus-server-to-method nth4))))
+		    (when (stringp (setq tmp-method (gnus-info-method info)))
+		      (setq tmp-method (gnus-server-to-method tmp-method))))
 		  ;; Only do the xrefs if the group has the same
 		  ;; select method as the group we have just read.
 		  (or (gnus-methods-equal-p
-		       nth4 (gnus-find-method-for-group from-newsgroup))
+		       tmp-method (gnus-find-method-for-group from-newsgroup))
 		      virtual
-		      (equal nth4 (setq method (gnus-find-method-for-group
-						from-newsgroup)))
-		      (and (equal (car nth4) (car method))
-			   (equal (nth 1 nth4) (nth 1 method))))
+		      (equal tmp-method
+			     (setq method (gnus-find-method-for-group
+					   from-newsgroup)))
+		      (and (equal (car tmp-method) (car method))
+			   (equal (nth 1 tmp-method) (nth 1 method))))
 		  gnus-use-cross-reference
 		  (or (not (eq gnus-use-cross-reference t))
 		      virtual
@@ -6310,7 +6312,7 @@ gnus-mark-xrefs-as-read
 
 (defun gnus-compute-read-articles (group articles)
   (let* ((entry (gnus-group-entry group))
-	 (info (nth 1 entry))
+	 (info (gnus-get-info entry))
 	 (active (gnus-active group))
 	 ninfo)
     (when entry
@@ -6347,7 +6349,7 @@ gnus-group-make-articles-read
   "Update the info of GROUP to say that ARTICLES are read."
   (let* ((num 0)
 	 (entry (gnus-group-entry group))
-	 (info (nth 1 entry))
+	 (info (gnus-get-info entry))
 	 (active (gnus-active group))
 	 (set-marks
 	  (gnus-method-option-p
@@ -6367,7 +6369,7 @@ gnus-group-make-articles-read
 	(gnus-undo-register
 	  `(progn
 	     (gnus-info-set-marks ',info ',(gnus-info-marks info) t)
-	     (gnus-info-set-read ',info ',(gnus-info-read info))
+	     (setf (gnus-info-read ',info) ',(gnus-info-read info))
 	     (gnus-get-unread-articles-in-group ',info (gnus-active ,group))
 	     (when ,set-marks
 	       (gnus-request-set-mark
@@ -6375,7 +6377,7 @@ gnus-group-make-articles-read
 	     (gnus-group-jump-to-group ,group)
 	     (gnus-group-update-group ,group t))))
       ;; Add the read articles to the range.
-      (gnus-info-set-read info range)
+      (setf (gnus-info-read info) range)
       (when set-marks
 	(gnus-request-set-mark group (list (list range 'add '(read)))))
       ;; Then we have to re-compute how many unread
@@ -6395,7 +6397,7 @@ gnus-group-make-articles-read
 	    (setq range (cdr range)))
 	  (setq num (- (cdr active) num))))
 	;; Update the number of unread articles.
-	(setcar entry num)
+	(setf (gnus-group-unread group) num)
 	;; Update the group buffer.
 	(unless (gnus-ephemeral-group-p group)
 	  (gnus-group-update-group group t))))))
@@ -10283,8 +10285,8 @@ gnus-summary-move-article
 	    (when (and (not (memq article gnus-newsgroup-unreads))
 		       (cdr art-group))
 	      (push 'read to-marks)
-	      (gnus-info-set-read
-	       info (gnus-add-to-range (gnus-info-read info)
+	      (setf (gnus-info-read info)
+		    (gnus-add-to-range (gnus-info-read info)
 				       (list (cdr art-group)))))
 
 	    ;; See whether the article is to be put in the cache.
@@ -12894,15 +12896,16 @@ gnus-update-read-articles
 	    (set-buffer gnus-group-buffer)
 	    (gnus-undo-register
 	      `(progn
+		 ;;FIXME: A better way of ensuring info completness?
 		 (gnus-info-set-marks ',info ',(gnus-info-marks info) t)
-		 (gnus-info-set-read ',info ',(gnus-info-read info))
+		 (setf (gnus-info-read ',info) ',(gnus-info-read info))
 		 (gnus-group-jump-to-group ,group)
 		 (gnus-get-unread-articles-in-group ',info
 						    (gnus-active ,group))
 		 (gnus-group-update-group ,group t)
 		 ,setmarkundo))))
 	;; Enter this list into the group info.
-	(gnus-info-set-read info read)
+	(setf (gnus-info-read info) read)
 	;; Set the number of unread articles in gnus-newsrc-hashtb.
 	(gnus-get-unread-articles-in-group info (gnus-active group))
 	t))))
diff --git a/lisp/gnus/gnus.el b/lisp/gnus/gnus.el
index 0673ac15f6..dd0c83ad94 100644
--- a/lisp/gnus/gnus.el
+++ b/lisp/gnus/gnus.el
@@ -3689,6 +3689,7 @@ gnus-group-set-parameter
 	    (setq new-params (append new-params (list (car old-params)))))
 	  (setq old-params (cdr old-params)))
 	(if (listp group)
+	    ;; FIXME: Address EXTEND.
 	    (gnus-info-set-params info new-params t)
 	  (gnus-group-set-info new-params (gnus-info-group info) 'params))))))
 
@@ -3704,14 +3705,15 @@ gnus-group-remove-parameter
 	  (setq params (delq name params))
 	  (while (assq name params)
 	    (gnus-alist-pull name params))
-	  (gnus-info-set-params info params))))))
+	  (setf (gnus-info-params info) params))))))
 
 (defun gnus-group-add-score (group &optional score)
   "Add SCORE to the GROUP score.
 If SCORE is nil, add 1 to the score of GROUP."
   (let ((info (gnus-get-info group)))
     (when info
-      (gnus-info-set-score info (+ (gnus-info-score info) (or score 1))))))
+      (setf (gnus-info-score info)
+	    (+ (gnus-info-score info) (or score 1))))))
 
 (defun gnus-short-group-name (group &optional levels)
   "Collapse GROUP name LEVELS.
diff --git a/lisp/gnus/nndiary.el b/lisp/gnus/nndiary.el
index f79d8f1707..88bb5651e2 100644
--- a/lisp/gnus/nndiary.el
+++ b/lisp/gnus/nndiary.el
@@ -795,8 +795,9 @@ nndiary-request-update-info
 	  (kill-buffer buf))
 	(setq unread (sort unread '<))
 	(and unread
-	     (gnus-info-set-read info (gnus-update-read-articles
-				       (gnus-info-group info) unread t)))
+	     (setf (gnus-info-read info)
+		   (gnus-update-read-articles
+		    (gnus-info-group info) unread t)))
 	))
     (run-hook-with-args 'nndiary-request-update-info-functions
 			(gnus-info-group info))
diff --git a/lisp/gnus/nndraft.el b/lisp/gnus/nndraft.el
index bc475ee295..cc9923164a 100644
--- a/lisp/gnus/nndraft.el
+++ b/lisp/gnus/nndraft.el
@@ -147,17 +147,17 @@ nndraft-request-restore-buffer
 
 (deffoo nndraft-request-update-info (group info &optional server)
   (nndraft-possibly-change-group group)
-  (gnus-info-set-read
-   info
-   (gnus-update-read-articles (gnus-group-prefixed-name group '(nndraft ""))
-			      (nndraft-articles) t))
-  (let ((marks (nth 3 info)))
+  (setf (gnus-info-read info)
+	(gnus-update-read-articles
+	 (gnus-group-prefixed-name group '(nndraft ""))
+	 (nndraft-articles) t))
+  (let ((marks (gnus-info-marks info)))
     (when marks
       ;; Nix out all marks except the `unsend'-able article marks.
-      (setcar (nthcdr 3 info)
-	      (if (assq 'unsend marks)
-		  (list (assq 'unsend marks))
-		nil))))
+      (setf (gnus-info-marks info)
+	    (if (assq 'unsend marks)
+		(list (assq 'unsend marks))
+	      nil))))
   t)
 
 (defun nndraft-generate-headers ()
diff --git a/lisp/gnus/nnimap.el b/lisp/gnus/nnimap.el
index 856ac75cd6..365f8e49d0 100644
--- a/lisp/gnus/nnimap.el
+++ b/lisp/gnus/nnimap.el
@@ -1620,7 +1620,7 @@ nnimap-update-info
 		       read)))
 	      (when (or (not (listp permanent-flags))
 			(memq '%Seen permanent-flags))
-		(gnus-info-set-read info read))
+		(setf (gnus-info-read info) read))
 	      ;; Update the marks.
 	      (setq marks (gnus-info-marks info))
 	      (dolist (type (cdr nnimap-mark-alist))
@@ -1663,6 +1663,7 @@ nnimap-update-info
 		(if old-unexists
 		    (setcdr old-unexists unexists)
 		  (push (cons 'unexist unexists) marks)))
+	      ;; FIXME: Handle EXTEND.
 	      (gnus-info-set-marks info marks t))))
 	;; Tell Gnus whether there are any \Recent messages in any of
 	;; the groups.
@@ -1680,14 +1681,13 @@ nnimap-update-info
 
 (defun nnimap-update-qresync-info (info existing vanished flags)
   ;; Add all the vanished articles to the list of read articles.
-  (gnus-info-set-read
-   info
-   (gnus-add-to-range
-    (gnus-add-to-range
-     (gnus-range-add (gnus-info-read info)
-		     vanished)
-     (cdr (assq '%Flagged flags)))
-    (cdr (assq '%Seen flags))))
+  (setf (gnus-info-read info)
+	(gnus-add-to-range
+	 (gnus-add-to-range
+	  (gnus-range-add (gnus-info-read info)
+			  vanished)
+	  (cdr (assq '%Flagged flags)))
+	 (cdr (assq '%Seen flags))))
   (let ((marks (gnus-info-marks info)))
     (dolist (type (cdr nnimap-mark-alist))
       (let ((ticks (assoc (car type) marks))
@@ -1707,6 +1707,7 @@ nnimap-update-qresync-info
 			(gnus-sorted-complement existing new-marks))))
 	  (when ticks
 	    (push (cons (car type) ticks) marks))
+	  ;; FIXME: Handle EXTEND.
 	  (gnus-info-set-marks info marks t))))
     ;; Add vanished to the list of unexisting articles.
     (when vanished
@@ -1715,6 +1716,7 @@ nnimap-update-qresync-info
 	(if old-unexists
 	    (setcdr old-unexists unexists)
 	  (push (cons 'unexist unexists) marks)))
+      ;; FIXME: Handle EXTEND.
       (gnus-info-set-marks info marks t))))
 
 (defun nnimap-imap-ranges-to-gnus-ranges (irange)
diff --git a/lisp/gnus/nnir.el b/lisp/gnus/nnir.el
index 7cb2d1615a..45fbadf23c 100644
--- a/lisp/gnus/nnir.el
+++ b/lisp/gnus/nnir.el
@@ -874,8 +874,8 @@ nnir-request-set-mark
 (deffoo nnir-request-update-info (group info &optional server)
   (nnir-possibly-change-group group server)
   ;; clear out all existing marks.
-  (gnus-info-set-marks info nil)
-  (gnus-info-set-read info nil)
+  (setf (gnus-info-marks info) nil)
+  (setf (gnus-info-read info) nil)
   (let ((group (gnus-group-guess-full-name-from-command-method group))
 	(articles-by-group
 	 (nnir-categorize
@@ -889,8 +889,8 @@ nnir-request-update-info
 	     (group-info (gnus-get-info (car group-articles)))
 	     (marks (gnus-info-marks group-info))
 	     (read (gnus-info-read group-info)))
-	(gnus-info-set-read
-	 info
+	(setf
+	 (gnus-info-read info)
 	 (gnus-add-to-range
 	  (gnus-info-read info)
 	  (delq nil
diff --git a/lisp/gnus/nnmaildir.el b/lisp/gnus/nnmaildir.el
index 0133fc6ce2..2fc773f74f 100644
--- a/lisp/gnus/nnmaildir.el
+++ b/lisp/gnus/nnmaildir.el
@@ -1000,7 +1000,8 @@ nnmaildir-request-update-info
 	    pgname (nnmaildir--pgname nnmaildir--cur-server gname)
 	    flist (nnmaildir--grp-flist group))
       (when (zerop (nnmaildir--grp-count group))
-	(gnus-info-set-read info nil)
+	(setf (gnus-info-read info) nil)
+	;; FIXME: Handle EXTEND.
 	(gnus-info-set-marks info nil 'extend)
 	(throw 'return info))
       (setq old-marks (cons 'read (gnus-info-read info))
@@ -1083,7 +1084,8 @@ nnmaildir-request-update-info
 	    (setq ranges (gnus-add-to-range ranges (sort article-list '<)))))
 	(if (eq mark 'read) (setq read ranges)
 	  (if ranges (setq marks (cons (cons mark ranges) marks)))))
-      (gnus-info-set-read info (gnus-range-add read missing))
+      (setf (gnus-info-read info) (gnus-range-add read missing))
+      ;; FIXME: Handle EXTEND.
       (gnus-info-set-marks info marks 'extend)
       (setf (nnmaildir--grp-mmth group) new-mmth)
       info)))
diff --git a/lisp/gnus/nnmairix.el b/lisp/gnus/nnmairix.el
index 6c5502ac3d..722cb95306 100644
--- a/lisp/gnus/nnmairix.el
+++ b/lisp/gnus/nnmairix.el
@@ -711,29 +711,27 @@ nnmairix-request-marks
 	    (nnimap-request-update-info-internal folder folderinfo nnmairix-backend-server)
 	  (nnmairix-call-backend "request-update-info" folder folderinfo nnmairix-backend-server))
 	;; set range of read articles
-	(gnus-info-set-read
-	 info
-	 (if docorr
-	     (nnmairix-map-range
-	      `(lambda (x) (+ x ,(cadr corr)))
-	      (gnus-info-read folderinfo))
-	   (gnus-info-read folderinfo)))
+	(setf (gnus-info-read info)
+	      (if docorr
+		  (nnmairix-map-range
+		   `(lambda (x) (+ x ,(cadr corr)))
+		   (gnus-info-read folderinfo))
+		(gnus-info-read folderinfo)))
 	;; set other marks
-	(gnus-info-set-marks
-	 info
-	 (if docorr
-	     (mapcar (lambda (cur)
-			 (cons
-			  (car cur)
-			  (nnmairix-map-range
-			   `(lambda (x) (+ x ,(cadr corr)))
-			   (list (cadr cur)))))
-		     (gnus-info-marks folderinfo))
-	   (gnus-info-marks folderinfo))))
+	(setf (gnus-info-marks info)
+	      (if docorr
+		  (mapcar (lambda (cur)
+			    (cons
+			     (car cur)
+			     (nnmairix-map-range
+			      `(lambda (x) (+ x ,(cadr corr)))
+			      (list (cadr cur)))))
+			  (gnus-info-marks folderinfo))
+		(gnus-info-marks folderinfo))))
       (when (eq readmarks 'unread)
-	(gnus-info-set-read info nil))
+	(setf (gnus-info-read info) nil))
       (when (eq readmarks 'read)
-	(gnus-info-set-read info (gnus-active qualgroup))))
+	(setf (gnus-info-read info) (gnus-active qualgroup))))
   t)
 
 (nnoo-define-skeleton nnmairix)
diff --git a/lisp/gnus/nnml.el b/lisp/gnus/nnml.el
index 302589bd6d..8d8d5ae83a 100644
--- a/lisp/gnus/nnml.el
+++ b/lisp/gnus/nnml.el
@@ -1067,7 +1067,7 @@ nnml-request-compact-group
 		  (when (gnus-member-of-range old-number read)
 		    (setq read (gnus-remove-from-range read (list old-number)))
 		    (setq read (gnus-add-to-range read (list new-number))))
-		  (gnus-info-set-read info read))
+		  (setf (gnus-info-read info) read))
 		;; 2 b/ marked articles:
 		(let ((oldmarks (gnus-info-marks info))
 		      mark newmarks)
@@ -1080,7 +1080,7 @@ nnml-request-compact-group
 		      (setcdr mark (gnus-add-to-range (cdr mark)
 						      (list new-number))))
 		    (push mark newmarks))
-		  (gnus-info-set-marks info newmarks))
+		  (setf (gnus-info-marks info) newmarks))
 		;; 3/ Update the NOV entry for this article:
 		(unless nnml-nov-is-evil
 		  (with-current-buffer (nnml-open-nov group)
diff --git a/lisp/gnus/nnvirtual.el b/lisp/gnus/nnvirtual.el
index 25f3413fcd..0a4d33cfab 100644
--- a/lisp/gnus/nnvirtual.el
+++ b/lisp/gnus/nnvirtual.el
@@ -307,11 +307,9 @@ nnvirtual-request-update-info
     ;; Install the precomputed lists atomically, so the virtual group
     ;; is not left in a half-way state in case of C-g.
     (gnus-atomic-progn
-      (setcar (cddr info) nnvirtual-mapping-reads)
-      (if (nthcdr 3 info)
-	  (setcar (nthcdr 3 info) nnvirtual-mapping-marks)
-	(when nnvirtual-mapping-marks
-	  (setcdr (nthcdr 2 info) (list nnvirtual-mapping-marks))))
+      (setf (gnus-info-read info) nnvirtual-mapping-reads)
+      (when nnvirtual-mapping-marks
+	(setf (gnus-info-marks info) nnvirtual-mapping-marks))
       (setq nnvirtual-info-installed t))
     t))
 
@@ -463,11 +461,10 @@ nnvirtual-update-read-and-marked
 	(dolist (group nnvirtual-component-groups)
 	  (when (and (setq info (gnus-get-info group))
 		     (gnus-info-marks info))
-	    (gnus-info-set-marks
-	     info
-	     (if (assq 'score (gnus-info-marks info))
-		 (list (assq 'score (gnus-info-marks info)))
-	       nil))))
+	    (setf (gnus-info-marks info)
+		  (if (assq 'score (gnus-info-marks info))
+		      (list (assq 'score (gnus-info-marks info)))
+		    nil))))
 
 	;; Ok, currently type-marks is an assq list with keys of a mark type,
 	;; with data of an assq list with keys of component group names
-- 
2.23.0