- (fn (or (cdr (assq name byte-compile-function-environment))
- (and (fboundp name) (symbol-function name)))))
- (if (null fn)
- (progn
- (byte-compile-warn "attempt to inline `%s' before it was defined"
- name)
- form)
- ;; else
- (when (and (consp fn) (eq (car fn) 'autoload))
- (load (nth 1 fn))
- (setq fn (or (and (fboundp name) (symbol-function name))
- (cdr (assq name byte-compile-function-environment)))))
- (if (and (consp fn) (eq (car fn) 'autoload))
- (error "File `%s' didn't define `%s'" (nth 1 fn) name))
- (cond
- ((and (symbolp fn) (not (eq fn t))) ;A function alias.
- (byte-compile-inline-expand (cons fn (cdr form))))
- ((and (byte-code-function-p fn)
- ;; FIXME: This works to inline old-style-byte-codes into
- ;; old-style-byte-codes, but not mixed cases (not sure
- ;; about new-style into new-style).
- (not lexical-binding)
- (not (and (>= (length fn) 7)
- (aref fn 6)))) ;6 = COMPILED_PUSH_ARGS
- ;; (message "Inlining %S byte-code" name)
- (fetch-bytecode fn)
- (let ((string (aref fn 1)))
- ;; Isn't it an error for `string' not to be unibyte?? --stef
- (if (fboundp 'string-as-unibyte)
- (setq string (string-as-unibyte string)))
- ;; `byte-compile-splice-in-already-compiled-code'
- ;; takes care of inlining the body.
- (cons `(lambda ,(aref fn 0)
- (byte-code ,string ,(aref fn 2) ,(aref fn 3)))
- (cdr form))))
- ((eq (car-safe fn) 'lambda)
- (macroexpand-all (cons fn (cdr form))
- byte-compile-macro-environment))
- (t ;; Give up on inlining.
- form)))))
+ (localfn (cdr (assq name byte-compile-function-environment)))
+ (fn (or localfn (symbol-function name))))
+ (when (autoloadp fn)
+ (autoload-do-load fn)
+ (setq fn (or (symbol-function name)
+ (cdr (assq name byte-compile-function-environment)))))
+ (pcase fn
+ (`nil
+ (byte-compile-warn "attempt to inline `%s' before it was defined"
+ name)
+ form)
+ (`(autoload . ,_)
+ (error "File `%s' didn't define `%s'" (nth 1 fn) name))
+ ((and (pred symbolp) (guard (not (eq fn t)))) ;A function alias.
+ (byte-compile-inline-expand (cons fn (cdr form))))
+ ((pred byte-code-function-p)
+ ;; (message "Inlining byte-code for %S!" name)
+ ;; The byte-code will be really inlined in byte-compile-unfold-bcf.
+ `(,fn ,@(cdr form)))
+ ((or `(lambda . ,_) `(closure . ,_))
+ (if (not (or (eq fn localfn) ;From the same file => same mode.
+ (eq (car fn) ;Same mode.
+ (if lexical-binding 'closure 'lambda))))
+ ;; While byte-compile-unfold-bcf can inline dynbind byte-code into
+ ;; letbind byte-code (or any other combination for that matter), we
+ ;; can only inline dynbind source into dynbind source or letbind
+ ;; source into letbind source.
+ (progn
+ ;; We can of course byte-compile the inlined function
+ ;; first, and then inline its byte-code.
+ (byte-compile name)
+ `(,(symbol-function name) ,@(cdr form)))
+ (let ((newfn (if (eq fn localfn)
+ ;; If `fn' is from the same file, it has already
+ ;; been preprocessed!
+ `(function ,fn)
+ (byte-compile-preprocess
+ (byte-compile--reify-function fn)))))
+ (if (eq (car-safe newfn) 'function)
+ (byte-compile-unfold-lambda `(,(cadr newfn) ,@(cdr form)))
+ ;; This can happen because of macroexp-warn-and-return &co.
+ (byte-compile-log-warning
+ (format "Inlining closure %S failed" name))
+ form))))
+
+ (t ;; Give up on inlining.
+ form))))