;;; -*- Mode:Lisp; Readtable:ZL; Package:USER; Base:8; Patch-File:T -*-
;;; Patch file for System version 121.54
;;; Reason:
;;;  fix compiler:breakoff to not screw up the lexical variable which
;;;  holds the throw tag for return froms out of lexical closures
;;;  in some obscure and hairy cases
;;;  don't ask me i just work here.   -EFH
;;; Written 9-May-87 00:34:34 by naha at site LMI Cambridge
;;; while running on Love from band 2
;;; with Experimental System 121.52, Experimental Lambda-Diag 15.0, Experimental ZMail 70.2, Experimental KERMIT 32.0, Experimental Unix-Interface 10.0, Experimental Local-File 72.0, Experimental FILE-Server 21.0, Experimental Tape 13.0, microcode 1733, SDU Boot Tape 3.13, SDU ROM 102, 121.35.



; From modified file DJ: L.SYS; QCP1.LISP#680 at 9-May-87 00:34:35
#8R COMPILER#: 
(COMPILER-LET ((*PACKAGE* (PKG-FIND-PACKAGE "COMPILER")))
  (PATCH-SOURCE-FILE "SYS: SYS; QCP1  "

(defun breakoff (x &optional lexical &aux fname fname-to-give local-name)
  (let ((non-instance-vars)
	(sfd self-flavor-declaration)
	;selfp
	)
    (dolist (home *vars*)
      (and (eq (var-type home) 'fef-local)
	   ;; Omit shadowed bindings.
	   (eq home (assq (var-name home) *vars*))
	   (pushnew (var-name home) non-instance-vars)))
    (dolist (elt *outer-context-vars*)
      (dolist (home elt)
	(push (var-name home) non-instance-vars)))
    (multiple-value-bind (vars-needed-lexically functions-needed-lexically
			  block-names go-tags)
	(cw-top-level-lambda-expression
	  x					;form
	  (append (if sfd (list* 'self (cddr sfd)))
		  non-instance-vars)		;variables we're interested in
	  (mapcar #'car *local-functions*)	;functions we're interested in
	  *function-environment*)
      (multiple-value-bind (nil decls nil)
	  (with-list (env *function-environment*)
	    (extract-declarations (if (memq (car x) '(named-subst named-lambda))
				      (cdddr x) (cddr x))
				  nil t env))
	(let ((downward (assq 'sys:downward-function decls))
	      tem)
	  (dolist (v vars-needed-lexically)
	    (cond ((and (memq v (cddr sfd)) (not (memq v non-instance-vars)))
		   (unless downward
		     (warn 'instance-variable-used-in-internal-lambda :unimplemented
			   "~The ~:[~;special ~]instance variable ~S of flavor ~S~@
				is being referenced by a lexically closed-over function.~@
				This will not work outside of the dynamic scope of ~S.~"
			   (memq v (cadr sfd)) v (car sfd) 'self)))
		  ((and (eq v 'self) sfd)
		   (unless downward
		     (warn 'self-used-in-internal-lambda :unimplemented
			   "~~S is being referenced by a lexically closed-over function.~@
			This will not, of course, work outside of the dynamic scope of ~S.~"
			   'self 'self)))
		  (t
		   ;; Note: if V is not on *VARS*, it must come from an outer lexical level.
		   ;; That is ok, and it still requires this LAMBDA to be lexical to access it.
		   (setq lexical t)
		   (setq tem (assq v *vars*))
		   (when tem
		     (pushnew 'fef-arg-used-in-lexical-closures (var-misc tem) :test #'eq)))))))
      (dolist (f functions-needed-lexically)
	(let ((tem (assq f *local-functions*)))
	  (when tem
	    (setq lexical t)
	    (pushnew 'fef-arg-used-in-lexical-closures
		     (var-misc (cadr tem)) :test #'eq))))
      (dolist (b block-names)
	(let ((tem (assq b *progdesc-environment*)))
	  (when tem
	    (setq lexical t)
	    ;; the flag may already have been set (by P1BLOCK) to a list representing a local variable
	    ;; home which will contain the throw tag.  something seems to be sorta duplicating the
	    ;; some of the work done by P1BLOCK.
	    ;; I admit I don't really understand what is going on here
	    ;; but I think this fixes it. -- EFH 4/9/87
	    (unless (progdesc-used-in-lexical-closures-flag tem)
	      (setf (progdesc-used-in-lexical-closures-flag tem) t)))))
      (dolist (g go-tags)
	(let ((tem (assq g *gotag-environment*)))
	  (when tem
	    (setq lexical t)
	    (setf (gotag-used-in-lexical-closures-flag tem) t)
	    (setf (progdesc-used-in-lexical-closures-flag (gotag-progdesc tem)) t))))))
  (if (and (eq (car x) 'named-lambda)
	   (not (memq (cadr x) *local-function-map*)))
      (setq local-name (cadr x))
      (setq local-name *breakoff-count*))
  (setq fname `(:internal ,function-to-be-defined ,*breakoff-count*)
	fname-to-give `(:internal ,name-to-give-function ,local-name))
  (push local-name *local-function-map*)
  (incf *breakoff-count*)
  (when lexical
    (incf *lexical-closure-count*))
;  (let ((local-decls local-declarations))
;>> this is already in there.
;    ;; Pass along the parent function's self-flavor declaration.
;    (if sfd (push `(:self-flavor . ,sfd) local-decls))
  (setq compiler-queue
	(nconc compiler-queue
	       (ncons
		 (make-compiler-queue-entry
		   :function-spec fname
		   :function-name fname-to-give
		   :definition x
		   :declarations local-declarations

		   ;; The t is a flag for RECORD-VARIABLES-USED-IN-LEXICAL-CLOSURES
		   ;; *VARS* at this point is a list of the lexically visible variables
		   ;; See  RECORD-VARIABLES-USED-IN-LEXICAL-CLOSURES for the gross detail

		   :variables  (when lexical
				 (cons (cons 't *vars*) *outer-context-vars*))
		   :local-functions (and lexical *local-functions*)
		   :progdescs (and lexical *progdesc-environment*)
		   :gotags (and lexical *gotag-environment*)
		   :function-environment (and lexical *function-environment*)
		   ))))
  (let ((tem `(breakoff-function ,fname)))
    (if lexical `(lexical-closure ,tem) tem)))

))
