Merge remote-tracking branch 'origin/stable-2.0'
authorAndy Wingo <wingo@pobox.com>
Mon, 26 Jan 2015 17:13:38 +0000 (18:13 +0100)
committerAndy Wingo <wingo@pobox.com>
Mon, 26 Jan 2015 17:13:38 +0000 (18:13 +0100)
Conflicts:
libguile/goops.c
libguile/vm-engine.h
module/oop/goops.scm
module/oop/goops/compile.scm
module/oop/goops/dispatch.scm
test-suite/tests/goops.test

1  2 
module/oop/goops.scm
test-suite/tests/goops.test

@@@ -1899,101 -470,6 +1899,111 @@@ function.
  ;;; {Methods}
  ;;;
  
-     (let lp ((specs (method-specializers m)) (types types))
 +;; Note: `a' and `b' can have unequal lengths (i.e. one can be one
 +;; element longer than the other when we have a dotted parameter
 +;; list). For instance, with the call
 +;;
 +;;   (M 1)
 +;;
 +;; with
 +;;
 +;;   (define-method M (a . l) ....)
 +;;   (define-method M (a) ....)
 +;;
 +;; we consider that the second method is more specific.
 +;;
 +;; Precondition: `a' and `b' are methods and are applicable to `types'.
 +(define (%method-more-specific? a b types)
 +  (let lp ((a-specializers (method-specializers a))
 +           (b-specializers (method-specializers b))
 +           (types types))
 +    (cond
 +     ;; (a) less specific than (a b ...) or (a . b)
 +     ((null? a-specializers) #t)
 +     ;; (a b ...) or (a . b) less specific than (a)
 +     ((null? b-specializers) #f)
 +     ;; (a . b) less specific than (a b ...)
 +     ((not (pair? a-specializers)) #f)
 +     ;; (a b ...) more specific than (a . b)
 +     ((not (pair? b-specializers)) #t)
 +     (else
 +      (let ((a-specializer (car a-specializers))
 +            (b-specializer (car b-specializers))
 +            (a-specializers (cdr a-specializers))
 +            (b-specializers (cdr b-specializers))
 +            (type (car types))
 +            (types (cdr types)))
 +        (if (eq? a-specializer b-specializer)
 +            (lp a-specializers b-specializers types)
 +            (let lp ((cpl (class-precedence-list type)))
 +              (let ((elt (car cpl)))
 +                (cond
 +                 ((eq? a-specializer elt) #t)
 +                 ((eq? b-specializer elt) #f)
 +                 (else (lp (cdr cpl))))))))))))
 +
 +(define (%sort-applicable-methods methods types)
 +  (sort methods (lambda (a b) (%method-more-specific? a b types))))
 +
 +(define (generic-function-methods obj)
 +  "Return the methods of the generic function @var{obj}."
 +  (define (fold-upward method-lists gf)
 +    (cond
 +     ((is-a? gf <extended-generic>)
 +      (let lp ((method-lists method-lists) (gfs (slot-ref gf 'extends)))
 +        (match gfs
 +          (() method-lists)
 +          ((gf . gfs)
 +           (lp (fold-upward (cons (slot-ref gf 'methods) method-lists) gf)
 +               gfs)))))
 +     (else method-lists)))
 +  (define (fold-downward method-lists gf)
 +    (let lp ((method-lists (cons (slot-ref gf 'methods) method-lists))
 +             (gfs (slot-ref gf 'extended-by)))
 +      (match gfs
 +        (() method-lists)
 +        ((gf . gfs)
 +         (lp (fold-downward method-lists gf) gfs)))))
 +  (unless (is-a? obj <generic>)
 +    (scm-error 'wrong-type-arg #f "Not a generic: ~S"
 +               (list obj) #f))
 +  (concatenate (fold-downward (fold-upward '() obj) obj)))
 +
 +(define (%compute-applicable-methods gf args)
 +  (define (method-applicable? m types)
-        ((null? specs) (null? types))
-        ((not (pair? specs)) #t)
-        ((null? types) #f)
++    (let ((specs (method-specializers m)))
 +      (cond
-         (and (memq (car specs) (class-precedence-list (car types)))
-              (lp (cdr specs) (cdr types)))))))
++       ((and (is-a? m <accessor-method>)
++             (or (null? specs) (null? types)
++                 (not (eq? (car specs) (car types)))))
++        ;; Slot accessor methods are added to each subclass with the
++        ;; slot.  They only apply to that specific concrete class, which
++        ;; appears as the first argument.
++        #f)
 +       (else
++        (let lp ((specs specs) (types types))
++          (cond
++           ((null? specs) (null? types))
++           ((not (pair? specs)) #t)
++           ((null? types) #f)
++           (else
++            (and (memq (car specs) (class-precedence-list (car types)))
++                 (lp (cdr specs) (cdr types))))))))))
 +  (let ((n (length args))
 +        (types (map class-of args)))
 +    (let lp ((methods (generic-function-methods gf))
 +             (applicable '()))
 +      (if (null? methods)
 +          (and (not (null? applicable))
 +               (%sort-applicable-methods applicable types))
 +          (let ((m (car methods)))
 +            (lp (cdr methods)
 +                (if (method-applicable? m types)
 +                    (cons m applicable)
 +                    applicable)))))))
 +
 +(define compute-applicable-methods %compute-applicable-methods)
 +
  (define (toplevel-define! name val)
    (module-define! (current-module) name val))
  
  ;;;
  (define (compute-slot-accessors class slots)
    (for-each
 -      (lambda (s g-n-s)
 -      (let ((getter-function (slot-definition-getter   s))
 -            (setter-function (slot-definition-setter   s))
 -            (accessor        (slot-definition-accessor s)))
 -        (if getter-function
 -            (add-method! getter-function
 -                         (compute-getter-method class g-n-s)))
 -        (if setter-function
 -            (add-method! setter-function
 -                         (compute-setter-method class g-n-s)))
 -        (if accessor
 -            (begin
 -              (add-method! accessor
 -                           (compute-getter-method class g-n-s))
 -              (add-method! (setter accessor)
 -                           (compute-setter-method class g-n-s))))))
 -      slots (slot-ref class 'getters-n-setters)))
 -
 -(define-method (compute-getter-method (class <class>) g-n-s)
 -  (let ((init-thunk (cadr g-n-s))
 -        (g-n-s (cddr g-n-s)))
 -    (make <accessor-method>
 -          #:specializers (list class)
 -          #:procedure (cond ((pair? g-n-s)
 -                             (make-generic-bound-check-getter (car g-n-s)))
 -                            (init-thunk
 -                             (standard-get g-n-s))
 -                            (else
 -                             (bound-check-get g-n-s)))
 -          #:slot-definition g-n-s)))
 -
 -(define-method (compute-setter-method (class <class>) g-n-s)
 -  (let ((init-thunk (cadr g-n-s))
 -        (g-n-s (cddr g-n-s)))
 -    (make <accessor-method>
 -      #:specializers (list class <top>)
 -      #:procedure (if (pair? g-n-s)
 -                      (cadr g-n-s)
 -                      (standard-set g-n-s))
 -      #:slot-definition g-n-s)))
 +   (lambda (slot)
 +     (let ((getter (%slot-definition-getter slot))
 +           (setter (%slot-definition-setter slot))
 +           (accessor-setter setter)
 +           (accessor (%slot-definition-accessor slot)))
 +       (when getter
 +         (add-method! getter (compute-getter-method class slot)))
 +       (when setter
 +         (add-method! setter (compute-setter-method class slot)))
 +       (when accessor
 +         (add-method! accessor (compute-getter-method class slot))
 +         (add-method! (accessor-setter accessor)
 +                      (compute-setter-method class slot)))))
 +   slots))
 +
 +(define-method (compute-getter-method (class <class>) slot)
-   (let ((name (slot-definition-name slot)))
-     (make <accessor-method>
-           #:specializers (list class)
-           #:procedure (lambda (o) (slot-ref o name))
-           #:slot-definition slot)))
++  (make <accessor-method>
++    #:specializers (list class)
++    #:procedure (slot-definition-slot-ref slot)
++    #:slot-definition slot))
 +
 +(define-method (compute-setter-method (class <class>) slot)
-   (let ((name (slot-definition-name slot)))
-     (make <accessor-method>
-       #:specializers (list class <top>)
-       #:procedure (lambda (o v) (slot-set! o name v))
-       #:slot-definition slot)))
++  (make <accessor-method>
++    #:specializers (list class <top>)
++    #:procedure (slot-definition-slot-set! slot)
++    #:slot-definition slot))
  
  (define (make-generic-bound-check-getter proc)
 -  (lambda (o) (assert-bound (proc o) o)))
 -
 -;; the idea is to compile the index into the procedure, for fastest
 -;; lookup.
 -
 -(eval-when (expand load eval)
 -  (define num-standard-pre-cache 20))
 -
 -(define-macro (define-standard-accessor-method form . body)
 -  (let ((name (caar form))
 -        (n-var (cadar form))
 -        (args (cdr form)))
 -    (define (make-one x)
 -      (define (body-trans form)
 -        (cond ((not (pair? form)) form)
 -              ((eq? (car form) 'struct-ref)
 -               `(,(car form) ,(cadr form) ,x))
 -              ((eq? (car form) 'struct-set!)
 -               `(,(car form) ,(cadr form) ,x ,(cadddr form)))
 -              (else
 -               (map body-trans form))))
 -      `(lambda ,args ,@(map body-trans body)))
 -    `(define ,name
 -       (let ((cache (vector ,@(map make-one (iota num-standard-pre-cache)))))
 -         (lambda (n)
 -           (if (< n ,num-standard-pre-cache)
 -               (vector-ref cache n)
 -               ((lambda (,n-var) (lambda ,args ,@body)) n)))))))
 -
 -(define-standard-accessor-method ((bound-check-get n) o)
 -  (let ((x (struct-ref o n)))
 -    (if (unbound? x)
 -        (slot-unbound o)
 -        x)))
 -
 -(define-standard-accessor-method ((standard-get n) o)
 -  (struct-ref o n))
 -
 -(define-standard-accessor-method ((standard-set n) o v)
 -  (struct-set! o n v))
 -
 -;;; compute-getters-n-setters
 -;;;
 -(define (compute-getters-n-setters class slots)
 -
 -  (define (compute-slot-init-function name s)
 -    (or (let ((thunk (slot-definition-init-thunk s)))
 -        (and thunk
 -             (if (thunk? thunk)
 -                   thunk
 -                   (goops-error "Bad init-thunk for slot `~S' in ~S: ~S"
 -                                name class thunk))))
 -      (let ((init (slot-definition-init-value s)))
 -        (and (not (unbound? init))
 -             (lambda () init)))))
 -
 -  (define (verify-accessors slot l)
 -    (cond ((integer? l))
 -        ((not (and (list? l) (= (length l) 2)))
 -         (goops-error "Bad getter and setter for slot `~S' in ~S: ~S"
 -                      slot class l))
 -        (else
 -         (let ((get (car l)) 
 -               (set (cadr l)))
 -           (if (not (procedure? get))
 -                 (goops-error "Bad getter closure for slot `~S' in ~S: ~S"
 -                            slot class get))
 -           (if (not (procedure? set))
 -                 (goops-error "Bad setter closure for slot `~S' in ~S: ~S"
 -                            slot class set))))))
 -
 -  (map (lambda (s)
 -       ;; The strange treatment of nfields is due to backward compatibility.
 -       (let* ((index (slot-ref class 'nfields))
 -              (g-n-s (compute-get-n-set class s))
 -              (size (- (slot-ref class 'nfields) index))
 -              (name  (slot-definition-name s)))
 -         ;; NOTE: The following is interdependent with C macros
 -         ;; defined above goops.c:scm_sys_prep_layout_x.
 -         ;;
 -         ;; For simple instance slots, we have the simplest form
 -         ;; '(name init-function . index)
 -         ;; For other slots we have
 -         ;; '(name init-function getter setter . alloc)
 -         ;; where alloc is:
 -         ;;   '(index size) for instance allocated slots
 -         ;;   '() for other slots
 -         (verify-accessors name g-n-s)
 -           (case (slot-definition-allocation s)
 -             ((#:each-subclass #:class)
 -              (unless (and (zero? size) (pair? g-n-s))
 -                (error "Class-allocated slots should not reserve fields"))
 -              ;; Don't initialize the slot; that's handled when the slot
 -              ;; is allocated, in compute-get-n-set.
 -              (cons name (cons #f g-n-s)))
 -             (else
 -              (cons name
 -                    (cons (compute-slot-init-function name s)
 -                          (if (or (integer? g-n-s)
 -                                  (zero? size))
 -                              g-n-s
 -                              (append g-n-s (list index size)))))))))
 -       slots))
 +  (lambda (o)
 +    (let ((val (proc o)))
 +      (if (unbound? val)
 +          (slot-unbound o)
 +          val))))
  
  ;;; compute-cpl
  ;;;
Simple merge