adjust class/c to compute projections once, instead of once per
use of the resulting contract
This commit is contained in:
parent
44e91ea961
commit
042ec40a7b
|
@ -2849,347 +2849,402 @@ An example
|
||||||
#t)
|
#t)
|
||||||
|
|
||||||
(define (class/c-proj ctc)
|
(define (class/c-proj ctc)
|
||||||
|
(define ctc-methods (class/c-methods ctc))
|
||||||
|
(define dynamic-features
|
||||||
|
(append (class/c-overrides ctc)
|
||||||
|
(class/c-augments ctc)
|
||||||
|
(class/c-augrides ctc)
|
||||||
|
(class/c-inherits ctc)))
|
||||||
|
(define dynamic-contracts
|
||||||
|
(append (class/c-override-contracts ctc)
|
||||||
|
(class/c-augment-contracts ctc)
|
||||||
|
(class/c-augride-contracts ctc)
|
||||||
|
(class/c-inherit-contracts ctc)))
|
||||||
(λ (blame)
|
(λ (blame)
|
||||||
(let ([bswap (blame-swap blame)])
|
(define bswap (blame-swap blame))
|
||||||
(λ (cls)
|
(define public-method-projections
|
||||||
(class/c-check-first-order ctc cls (λ args (apply raise-blame-error blame cls args)))
|
(for/list ([name (in-list ctc-methods)]
|
||||||
(let* ([name (class-name cls)]
|
[c (in-list (class/c-method-contracts ctc))])
|
||||||
[never-wrapped? (eq? (class-orig-cls cls) cls)]
|
(and c
|
||||||
;; Only add a new slot if we're not projecting an already contracted class.
|
((contract-projection c) (blame-add-method-context blame name)))))
|
||||||
[supers (if never-wrapped?
|
(define super-projections
|
||||||
(list->vector (append (vector->list (class-supers cls))
|
(for/list ([name (in-list (class/c-supers ctc))]
|
||||||
(list #f)))
|
[c (in-list (class/c-super-contracts ctc))])
|
||||||
(list->vector (vector->list (class-supers cls))))]
|
(and c
|
||||||
[pos (if never-wrapped?
|
((contract-projection c) (blame-add-method-context blame name)))))
|
||||||
(add1 (class-pos cls))
|
(define inner-projections
|
||||||
(class-pos cls))]
|
(for/list ([name (in-list (class/c-inners ctc))]
|
||||||
[method-width (class-method-width cls)]
|
[c (in-list (class/c-inner-contracts ctc))])
|
||||||
[method-ht (class-method-ht cls)]
|
(and c
|
||||||
[method-ictcs (class-method-ictcs cls)]
|
((contract-projection c) (blame-add-method-context bswap name)))))
|
||||||
[ctc-methods (class/c-methods ctc)]
|
|
||||||
[dynamic-features
|
(define internal-field-projections
|
||||||
(append (class/c-overrides ctc)
|
(for/list ([f (in-list (class/c-fields ctc))]
|
||||||
(class/c-augments ctc)
|
[c (in-list (class/c-field-contracts ctc))])
|
||||||
(class/c-augrides ctc)
|
(and c
|
||||||
(class/c-inherits ctc))]
|
(let ([p-pos ((contract-projection c) (blame-add-context blame (format "the ~a field in" f)))]
|
||||||
[dynamic-contracts
|
[p-neg ((contract-projection c) (blame-add-context bswap (format "the ~a field in" f)))])
|
||||||
(append (class/c-override-contracts ctc)
|
(cons p-pos p-neg)))))
|
||||||
(class/c-augment-contracts ctc)
|
(define external-field-projections
|
||||||
(class/c-augride-contracts ctc)
|
(for/list ([f (in-list (class/c-inherit-fields ctc))]
|
||||||
(class/c-inherit-contracts ctc))]
|
[c (in-list (class/c-inherit-field-contracts ctc))])
|
||||||
[methods (if (null? ctc-methods)
|
(and c
|
||||||
(class-methods cls)
|
(let ([p-pos ((contract-projection c) blame)]
|
||||||
(make-vector method-width))]
|
[p-neg ((contract-projection c) bswap)])
|
||||||
[super-methods (if (null? (class/c-supers ctc))
|
(cons p-pos p-neg)))))
|
||||||
(class-super-methods cls)
|
|
||||||
(make-vector method-width))]
|
(define override-projections
|
||||||
[int-methods (if (null? dynamic-features)
|
(for/list ([m (in-list (class/c-overrides ctc))]
|
||||||
(class-int-methods cls)
|
[c (in-list (class/c-override-contracts ctc))])
|
||||||
|
(and c
|
||||||
|
((contract-projection c) (blame-add-method-context bswap m)))))
|
||||||
|
|
||||||
|
(define augment/augride-projections
|
||||||
|
(for/list ([m (in-list (append (class/c-augments ctc)
|
||||||
|
(class/c-augrides ctc)))]
|
||||||
|
[c (in-list (append (class/c-augment-contracts ctc)
|
||||||
|
(class/c-augride-contracts ctc)))])
|
||||||
|
(and c
|
||||||
|
((contract-projection c) (blame-add-method-context blame m)))))
|
||||||
|
|
||||||
|
(define inherit-projections
|
||||||
|
(for/list ([m (in-list (class/c-inherits ctc))]
|
||||||
|
[c (in-list (class/c-inherit-contracts ctc))])
|
||||||
|
(and c
|
||||||
|
((contract-projection c) (blame-add-method-context blame m)))))
|
||||||
|
|
||||||
|
;; zip the inits and contracts together for ordered selection
|
||||||
|
(define inits+contracts
|
||||||
|
(for/list ([init (in-list (class/c-inits ctc))]
|
||||||
|
[ctc (in-list (class/c-init-contracts ctc))])
|
||||||
|
(list init ((contract-projection ctc) bswap))))
|
||||||
|
|
||||||
|
(λ (cls)
|
||||||
|
(class/c-check-first-order ctc cls (λ args (apply raise-blame-error blame cls args)))
|
||||||
|
(let* ([name (class-name cls)]
|
||||||
|
[never-wrapped? (eq? (class-orig-cls cls) cls)]
|
||||||
|
;; Only add a new slot if we're not projecting an already contracted class.
|
||||||
|
[supers (if never-wrapped?
|
||||||
|
(list->vector (append (vector->list (class-supers cls))
|
||||||
|
(list #f)))
|
||||||
|
(list->vector (vector->list (class-supers cls))))]
|
||||||
|
[pos (if never-wrapped?
|
||||||
|
(add1 (class-pos cls))
|
||||||
|
(class-pos cls))]
|
||||||
|
[method-width (class-method-width cls)]
|
||||||
|
[method-ht (class-method-ht cls)]
|
||||||
|
[method-ictcs (class-method-ictcs cls)]
|
||||||
|
[methods (if (null? ctc-methods)
|
||||||
|
(class-methods cls)
|
||||||
|
(make-vector method-width))]
|
||||||
|
[super-methods (if (null? (class/c-supers ctc))
|
||||||
|
(class-super-methods cls)
|
||||||
(make-vector method-width))]
|
(make-vector method-width))]
|
||||||
[inner-projs (if (null? (class/c-inners ctc))
|
[int-methods (if (null? dynamic-features)
|
||||||
(class-inner-projs cls)
|
(class-int-methods cls)
|
||||||
|
(make-vector method-width))]
|
||||||
|
[inner-projs (if (null? (class/c-inners ctc))
|
||||||
|
(class-inner-projs cls)
|
||||||
|
(make-vector method-width))]
|
||||||
|
[dynamic-idxs (if (null? dynamic-features)
|
||||||
|
(class-dynamic-idxs cls)
|
||||||
|
(make-vector method-width))]
|
||||||
|
[dynamic-projs (if (null? dynamic-features)
|
||||||
|
(class-dynamic-projs cls)
|
||||||
(make-vector method-width))]
|
(make-vector method-width))]
|
||||||
[dynamic-idxs (if (null? dynamic-features)
|
[field-pub-width (class-field-pub-width cls)]
|
||||||
(class-dynamic-idxs cls)
|
[no-field-ctcs? (and (null? (class/c-fields ctc))
|
||||||
(make-vector method-width))]
|
(null? (class/c-inherit-fields ctc)))]
|
||||||
[dynamic-projs (if (null? dynamic-features)
|
[field-ht (if no-field-ctcs?
|
||||||
(class-dynamic-projs cls)
|
(class-field-ht cls)
|
||||||
(make-vector method-width))]
|
(hash-copy (class-field-ht cls)))]
|
||||||
[field-pub-width (class-field-pub-width cls)]
|
[init (class-init cls)]
|
||||||
[no-field-ctcs? (and (null? (class/c-fields ctc))
|
[class-make (if name
|
||||||
(null? (class/c-inherit-fields ctc)))]
|
(make-naming-constructor struct:class name "class")
|
||||||
[field-ht (if no-field-ctcs?
|
make-class)]
|
||||||
(class-field-ht cls)
|
[c (class-make name
|
||||||
(hash-copy (class-field-ht cls)))]
|
pos
|
||||||
[init (class-init cls)]
|
supers
|
||||||
[class-make (if name
|
(class-self-interface cls)
|
||||||
(make-naming-constructor struct:class name "class")
|
void ;; No inspecting
|
||||||
make-class)]
|
|
||||||
[c (class-make name
|
|
||||||
pos
|
|
||||||
supers
|
|
||||||
(class-self-interface cls)
|
|
||||||
void ;; No inspecting
|
|
||||||
|
|
||||||
method-width
|
method-width
|
||||||
method-ht
|
method-ht
|
||||||
(class-method-ids cls)
|
(class-method-ids cls)
|
||||||
(class-abstract-ids cls)
|
(class-abstract-ids cls)
|
||||||
(remq* ctc-methods method-ictcs)
|
(remq* ctc-methods method-ictcs)
|
||||||
|
|
||||||
#f
|
#f
|
||||||
|
|
||||||
methods
|
methods
|
||||||
super-methods
|
super-methods
|
||||||
int-methods
|
int-methods
|
||||||
(class-beta-methods cls)
|
(class-beta-methods cls)
|
||||||
(class-meth-flags cls)
|
(class-meth-flags cls)
|
||||||
|
|
||||||
inner-projs
|
inner-projs
|
||||||
dynamic-idxs
|
dynamic-idxs
|
||||||
dynamic-projs
|
dynamic-projs
|
||||||
|
|
||||||
(class-field-width cls)
|
(class-field-width cls)
|
||||||
field-pub-width
|
field-pub-width
|
||||||
field-ht
|
field-ht
|
||||||
(class-field-ids cls)
|
(class-field-ids cls)
|
||||||
|
|
||||||
'struct:object 'object? 'make-object
|
'struct:object 'object? 'make-object
|
||||||
'field-ref 'field-set!
|
'field-ref 'field-set!
|
||||||
|
|
||||||
;; class/c introduced subclasses do not consume init args
|
;; class/c introduced subclasses do not consume init args
|
||||||
null
|
null
|
||||||
'normal
|
'normal
|
||||||
#f
|
#f
|
||||||
|
|
||||||
(class-orig-cls cls)
|
(class-orig-cls cls)
|
||||||
#f #f ; serializer is never set
|
#f #f ; serializer is never set
|
||||||
#f)]
|
#f)]
|
||||||
[obj-name (if name
|
[obj-name (if name
|
||||||
(string->symbol (format "object:~a" name))
|
(string->symbol (format "object:~a" name))
|
||||||
'object)])
|
'object)])
|
||||||
(define (make-method proc meth-name)
|
(define (make-method proc meth-name)
|
||||||
(procedure-rename
|
(procedure-rename
|
||||||
(procedure->method proc)
|
(procedure->method proc)
|
||||||
(string->symbol
|
(string->symbol
|
||||||
(format "~a method~a~a"
|
(format "~a method~a~a"
|
||||||
meth-name
|
meth-name
|
||||||
(if name " in " "")
|
(if name " in " "")
|
||||||
(or name "")))))
|
(or name "")))))
|
||||||
|
|
||||||
(vector-set! supers pos c)
|
(vector-set! supers pos c)
|
||||||
|
|
||||||
;; --- Make the new object struct ---
|
;; --- Make the new object struct ---
|
||||||
(let-values ([(struct:object object-make object? object-field-ref object-field-set!)
|
(let-values ([(struct:object object-make object? object-field-ref object-field-set!)
|
||||||
(make-struct-type obj-name
|
(make-struct-type obj-name
|
||||||
(class-struct:object cls)
|
(class-struct:object cls)
|
||||||
0 ;; No init fields
|
0 ;; No init fields
|
||||||
0 ;; No new fields in this class replacement
|
0 ;; No new fields in this class replacement
|
||||||
undefined
|
undefined
|
||||||
;; Map object property to class:
|
;; Map object property to class:
|
||||||
(list (cons prop:object c)))])
|
(list (cons prop:object c)))])
|
||||||
(set-class-struct:object! c struct:object)
|
(set-class-struct:object! c struct:object)
|
||||||
(set-class-object?! c object?)
|
(set-class-object?! c object?)
|
||||||
(set-class-make-object! c object-make)
|
(set-class-make-object! c object-make)
|
||||||
(set-class-field-ref! c object-field-ref)
|
(set-class-field-ref! c object-field-ref)
|
||||||
(set-class-field-set!! c object-field-set!))
|
(set-class-field-set!! c object-field-set!))
|
||||||
|
|
||||||
;; Handle public method contracts
|
;; Handle public method contracts
|
||||||
(unless (null? ctc-methods)
|
(unless (null? ctc-methods)
|
||||||
;; First, fill in from old methods
|
;; First, fill in from old methods
|
||||||
(vector-copy! methods 0 (class-methods cls))
|
(vector-copy! methods 0 (class-methods cls))
|
||||||
;; Concretize any interface contracts handled by this ctc
|
;; Concretize any interface contracts handled by this ctc
|
||||||
(unless (null? (class-method-ictcs cls))
|
(unless (null? (class-method-ictcs cls))
|
||||||
(for ([m (in-list (class-method-ictcs cls))])
|
(for ([m (in-list (class-method-ictcs cls))])
|
||||||
;; only concretize if class/c takes responsibility for it
|
;; only concretize if class/c takes responsibility for it
|
||||||
(when (memq m ctc-methods)
|
(when (memq m ctc-methods)
|
||||||
(define i (hash-ref method-ht m))
|
|
||||||
(define entry (vector-ref methods i))
|
|
||||||
;; we're passing through a contract boundary, so the positive blame (aka
|
|
||||||
;; value server) is taking responsibility for any interface-contracted
|
|
||||||
;; methods)
|
|
||||||
(define info (replace-ictc-blame (cadr entry) #f (blame-positive blame)))
|
|
||||||
(vector-set! methods i (concretize-ictc-method m (car entry) info)))))
|
|
||||||
;; Now apply projections
|
|
||||||
(for ([m (in-list ctc-methods)]
|
|
||||||
[c (in-list (class/c-method-contracts ctc))])
|
|
||||||
(when c
|
|
||||||
(define i (hash-ref method-ht m))
|
(define i (hash-ref method-ht m))
|
||||||
(define mp (vector-ref methods i))
|
(define entry (vector-ref methods i))
|
||||||
(define p ((contract-projection c) (blame-add-method-context blame mp)))
|
;; we're passing through a contract boundary, so the positive blame (aka
|
||||||
(vector-set! methods i (make-method (p mp) m)))))
|
;; value server) is taking responsibility for any interface-contracted
|
||||||
|
;; methods)
|
||||||
|
(define info (replace-ictc-blame (cadr entry) #f (blame-positive blame)))
|
||||||
|
(vector-set! methods i (concretize-ictc-method m (car entry) info)))))
|
||||||
|
;; Now apply projections
|
||||||
|
(for ([m (in-list ctc-methods)]
|
||||||
|
[p (in-list public-method-projections)])
|
||||||
|
(when p
|
||||||
|
(define i (hash-ref method-ht m))
|
||||||
|
(define mp (vector-ref methods i))
|
||||||
|
(vector-set! methods i (make-method (p mp) m)))))
|
||||||
|
|
||||||
;; Handle super contracts
|
;; Handle super contracts
|
||||||
(unless (null? (class/c-supers ctc))
|
(unless (null? (class/c-supers ctc))
|
||||||
;; First, fill in from old (possibly contracted) super methods
|
;; First, fill in from old (possibly contracted) super methods
|
||||||
(vector-copy! super-methods 0 (class-super-methods cls))
|
(vector-copy! super-methods 0 (class-super-methods cls))
|
||||||
;; Now apply projections.
|
;; Now apply projections.
|
||||||
(for ([m (in-list (class/c-supers ctc))]
|
(for ([m (in-list (class/c-supers ctc))]
|
||||||
[c (in-list (class/c-super-contracts ctc))])
|
[p (in-list super-projections)])
|
||||||
|
(when p
|
||||||
|
(define i (hash-ref method-ht m))
|
||||||
|
(define mp (vector-ref super-methods i))
|
||||||
|
(vector-set! super-methods i (make-method (p mp) m)))))
|
||||||
|
|
||||||
|
;; Add inner projections
|
||||||
|
(unless (null? (class/c-inners ctc))
|
||||||
|
(vector-copy! inner-projs 0 (class-inner-projs cls))
|
||||||
|
(for ([m (in-list (class/c-inners ctc))]
|
||||||
|
[p (in-list inner-projections)])
|
||||||
|
(when p
|
||||||
|
(define i (hash-ref method-ht m))
|
||||||
|
(define old-proj (vector-ref inner-projs i))
|
||||||
|
(vector-set! inner-projs i (λ (v) (old-proj (p v)))))))
|
||||||
|
|
||||||
|
;; Handle both internal and external field contracts
|
||||||
|
(unless no-field-ctcs?
|
||||||
|
(for ([f (in-list (class/c-fields ctc))]
|
||||||
|
[p-pr (in-list internal-field-projections)])
|
||||||
|
(when p-pr
|
||||||
|
(define fi (hash-ref field-ht f))
|
||||||
|
(define p-pos (car p-pr))
|
||||||
|
(define p-neg (cdr p-pr))
|
||||||
|
(hash-set! field-ht f (field-info-extend-external fi p-pos p-neg))))
|
||||||
|
(for ([f (in-list (class/c-inherit-fields ctc))]
|
||||||
|
[p-pr (in-list external-field-projections)])
|
||||||
|
(when p-pr
|
||||||
|
(define fi (hash-ref field-ht f))
|
||||||
|
(define p-pos (car p-pr))
|
||||||
|
(define p-neg (cdr p-pr))
|
||||||
|
(hash-set! field-ht f (field-info-extend-internal fi p-pos p-neg)))))
|
||||||
|
|
||||||
|
;; Now the trickiest of them all, internal dynamic dispatch.
|
||||||
|
;; First we update any dynamic indexes, as applicable.
|
||||||
|
(let ([old-idxs (class-dynamic-idxs (class-orig-cls cls))])
|
||||||
|
(unless (null? dynamic-features)
|
||||||
|
;; Go ahead and do all the copies here.
|
||||||
|
(vector-copy! dynamic-projs 0 (class-dynamic-projs cls))
|
||||||
|
(vector-copy! int-methods 0 (class-int-methods cls))
|
||||||
|
(vector-copy! dynamic-idxs 0 (class-dynamic-idxs cls))
|
||||||
|
(for ([m (in-list dynamic-features)]
|
||||||
|
[c (in-list dynamic-contracts)])
|
||||||
(when c
|
(when c
|
||||||
(define i (hash-ref method-ht m))
|
(let* ([i (hash-ref method-ht m)]
|
||||||
(define mp (vector-ref super-methods i))
|
[old-idx (vector-ref old-idxs i)]
|
||||||
(define p ((contract-projection c) (blame-add-method-context blame mp)))
|
[new-idx (vector-ref dynamic-idxs i)])
|
||||||
(vector-set! super-methods i (make-method (p mp) m)))))
|
;; We need to extend all the vectors, so let's do that here.
|
||||||
|
(when (= old-idx new-idx)
|
||||||
|
(let* ([new-idx (add1 old-idx)]
|
||||||
|
[new-proj-vec (make-vector (add1 new-idx))]
|
||||||
|
[old-proj-vec (vector-ref dynamic-projs i)]
|
||||||
|
[new-int-vec (make-vector (add1 new-idx))]
|
||||||
|
[old-int-vec (vector-ref int-methods i)])
|
||||||
|
(vector-set! dynamic-idxs i new-idx)
|
||||||
|
(vector-copy! new-proj-vec 0 old-proj-vec)
|
||||||
|
(vector-set! new-proj-vec new-idx identity)
|
||||||
|
(vector-set! dynamic-projs i new-proj-vec)
|
||||||
|
(vector-copy! new-int-vec 0 old-int-vec)
|
||||||
|
;; Just copy over the last entry here. We'll
|
||||||
|
;; update it appropriately later.
|
||||||
|
(vector-set! new-int-vec new-idx
|
||||||
|
(vector-ref old-int-vec old-idx))
|
||||||
|
(vector-set! int-methods i new-int-vec)))))))
|
||||||
|
|
||||||
;; Add inner projections
|
;; Now we handle updating override contracts... here we just
|
||||||
(unless (null? (class/c-inners ctc))
|
;; update the projections, and not the methods (which we must
|
||||||
(vector-copy! inner-projs 0 (class-inner-projs cls))
|
;; do during class composition).
|
||||||
(for ([m (in-list (class/c-inners ctc))]
|
(unless (null? (class/c-overrides ctc))
|
||||||
[c (in-list (class/c-inner-contracts ctc))])
|
(for ([m (in-list (class/c-overrides ctc))]
|
||||||
(when c
|
[p (in-list override-projections)])
|
||||||
(define i (hash-ref method-ht m))
|
(when p
|
||||||
(define old-proj (vector-ref inner-projs i))
|
(let* ([i (hash-ref method-ht m)]
|
||||||
(define p ((contract-projection c) (blame-add-method-context bswap old-proj)))
|
[old-idx (vector-ref old-idxs i)]
|
||||||
(vector-set! inner-projs i (λ (v) (old-proj (p v)))))))
|
[proj-vec (vector-ref dynamic-projs i)]
|
||||||
|
[old-proj (vector-ref proj-vec old-idx)])
|
||||||
|
(vector-set! proj-vec old-idx (λ (v) (old-proj (p v))))))))
|
||||||
|
|
||||||
;; Handle both internal and external field contracts
|
;; For augment and augride contracts, we both update the projection
|
||||||
(unless no-field-ctcs?
|
;; and go ahead and apply the projection to the last slot (which will
|
||||||
(for ([f (in-list (class/c-fields ctc))]
|
;; only be used by later classes).
|
||||||
[c (in-list (class/c-field-contracts ctc))])
|
(unless (and (null? (class/c-augments ctc))
|
||||||
(when c
|
(null? (class/c-augrides ctc)))
|
||||||
(let ([fi (hash-ref field-ht f)]
|
(for ([m (in-list (append (class/c-augments ctc)
|
||||||
[p-pos ((contract-projection c) (blame-add-context blame (format "the ~a field in" f)))]
|
(class/c-augrides ctc)))]
|
||||||
[p-neg ((contract-projection c) (blame-add-context bswap (format "the ~a field in" f)))])
|
[p (in-list augment/augride-projections)])
|
||||||
(hash-set! field-ht f (field-info-extend-external fi p-pos p-neg)))))
|
(when p
|
||||||
(for ([f (in-list (class/c-inherit-fields ctc))]
|
(let* ([i (hash-ref method-ht m)]
|
||||||
[c (in-list (class/c-inherit-field-contracts ctc))])
|
[old-idx (vector-ref old-idxs i)]
|
||||||
(when c
|
[new-idx (vector-ref dynamic-idxs i)]
|
||||||
(let ([fi (hash-ref field-ht f)]
|
[proj-vec (vector-ref dynamic-projs i)]
|
||||||
[p-pos ((contract-projection c) blame)]
|
[int-vec (vector-ref int-methods i)]
|
||||||
[p-neg ((contract-projection c) bswap)])
|
[old-proj (vector-ref proj-vec old-idx)])
|
||||||
(hash-set! field-ht f (field-info-extend-internal fi p-pos p-neg))))))
|
(vector-set! proj-vec old-idx (λ (v) (p (old-proj v))))
|
||||||
|
(vector-set! int-vec new-idx
|
||||||
|
(make-method (p (vector-ref int-vec new-idx)) m))))))
|
||||||
|
|
||||||
;; Now the trickiest of them all, internal dynamic dispatch.
|
;; Now (that things have been extended appropriately) we handle
|
||||||
;; First we update any dynamic indexes, as applicable.
|
;; inherits.
|
||||||
(let ([old-idxs (class-dynamic-idxs (class-orig-cls cls))])
|
(unless (null? (class/c-inherits ctc))
|
||||||
(unless (null? dynamic-features)
|
(for ([m (in-list (class/c-inherits ctc))]
|
||||||
;; Go ahead and do all the copies here.
|
[p (in-list inherit-projections)])
|
||||||
(vector-copy! dynamic-projs 0 (class-dynamic-projs cls))
|
(when p
|
||||||
(vector-copy! int-methods 0 (class-int-methods cls))
|
(let* ([i (hash-ref method-ht m)]
|
||||||
(vector-copy! dynamic-idxs 0 (class-dynamic-idxs cls))
|
[new-idx (vector-ref dynamic-idxs i)]
|
||||||
(for ([m (in-list dynamic-features)]
|
[int-vec (vector-ref int-methods i)])
|
||||||
[c (in-list dynamic-contracts)])
|
(vector-set! int-vec new-idx
|
||||||
(when c
|
(make-method (p (vector-ref int-vec new-idx)) m)))))))
|
||||||
(let* ([i (hash-ref method-ht m)]
|
|
||||||
[old-idx (vector-ref old-idxs i)]
|
|
||||||
[new-idx (vector-ref dynamic-idxs i)])
|
|
||||||
;; We need to extend all the vectors, so let's do that here.
|
|
||||||
(when (= old-idx new-idx)
|
|
||||||
(let* ([new-idx (add1 old-idx)]
|
|
||||||
[new-proj-vec (make-vector (add1 new-idx))]
|
|
||||||
[old-proj-vec (vector-ref dynamic-projs i)]
|
|
||||||
[new-int-vec (make-vector (add1 new-idx))]
|
|
||||||
[old-int-vec (vector-ref int-methods i)])
|
|
||||||
(vector-set! dynamic-idxs i new-idx)
|
|
||||||
(vector-copy! new-proj-vec 0 old-proj-vec)
|
|
||||||
(vector-set! new-proj-vec new-idx identity)
|
|
||||||
(vector-set! dynamic-projs i new-proj-vec)
|
|
||||||
(vector-copy! new-int-vec 0 old-int-vec)
|
|
||||||
;; Just copy over the last entry here. We'll
|
|
||||||
;; update it appropriately later.
|
|
||||||
(vector-set! new-int-vec new-idx
|
|
||||||
(vector-ref old-int-vec old-idx))
|
|
||||||
(vector-set! int-methods i new-int-vec)))))))
|
|
||||||
|
|
||||||
;; Now we handle updating override contracts... here we just
|
;; Unlike the others, we always want to do this, even if there are no init contracts,
|
||||||
;; update the projections, and not the methods (which we must
|
;; since we still need to handle either calling the previous class/c's init or
|
||||||
;; do during class composition).
|
;; calling continue-make-super appropriately.
|
||||||
(unless (null? (class/c-overrides ctc))
|
(let ()
|
||||||
(for ([m (in-list (class/c-overrides ctc))]
|
;; grab all the inits+contracts that involve the same init arg
|
||||||
[c (in-list (class/c-override-contracts ctc))])
|
;; (assumes that inits and contracts were sorted in class/c creation)
|
||||||
(when c
|
(define (grab-same-inits lst)
|
||||||
(let* ([i (hash-ref method-ht m)]
|
(if (null? lst)
|
||||||
[p ((contract-projection c) (blame-add-method-context bswap i))]
|
(values null null)
|
||||||
[old-idx (vector-ref old-idxs i)]
|
(let loop ([inits/c (cdr lst)]
|
||||||
[proj-vec (vector-ref dynamic-projs i)]
|
[prefix (list (car lst))])
|
||||||
[old-proj (vector-ref proj-vec old-idx)])
|
(cond
|
||||||
(vector-set! proj-vec old-idx (λ (v) (old-proj (p v))))))))
|
[(null? inits/c)
|
||||||
|
(values (reverse prefix) inits/c)]
|
||||||
|
[(eq? (list-ref (car inits/c) 0) (list-ref (car prefix) 0))
|
||||||
|
(loop (cdr inits/c)
|
||||||
|
(cons (car inits/c) prefix))]
|
||||||
|
[else (values (reverse prefix) inits/c)]))))
|
||||||
|
;; run through the list of init-args and apply contracts for same-named
|
||||||
|
;; init args
|
||||||
|
(define (apply-contracts inits/c init-args)
|
||||||
|
(let loop ([init-args init-args]
|
||||||
|
[inits/c inits/c]
|
||||||
|
[handled-args null])
|
||||||
|
(cond
|
||||||
|
[(null? init-args)
|
||||||
|
(reverse handled-args)]
|
||||||
|
[(null? inits/c)
|
||||||
|
(append (reverse handled-args) init-args)]
|
||||||
|
[(eq? (list-ref (car inits/c) 0) (car (car init-args)))
|
||||||
|
(let ([init-arg (car init-args)]
|
||||||
|
[p (list-ref (car inits/c) 1)])
|
||||||
|
(loop (cdr init-args)
|
||||||
|
(cdr inits/c)
|
||||||
|
(cons (cons (car init-arg) (p (cdr init-arg)))
|
||||||
|
handled-args)))]
|
||||||
|
[else (loop (cdr init-args)
|
||||||
|
inits/c
|
||||||
|
(cons (car init-args) handled-args))])))
|
||||||
|
(set-class-init!
|
||||||
|
c
|
||||||
|
(lambda (the-obj super-go si_c si_inited? si_leftovers init-args)
|
||||||
|
(let ([init-args
|
||||||
|
(let loop ([inits/c inits+contracts]
|
||||||
|
[handled-args init-args])
|
||||||
|
(if (null? inits/c)
|
||||||
|
handled-args
|
||||||
|
(let-values ([(prefix suffix) (grab-same-inits inits/c)])
|
||||||
|
(loop suffix
|
||||||
|
(apply-contracts prefix init-args)))))])
|
||||||
|
;; Since we never consume init args, we can ignore si_leftovers
|
||||||
|
;; since init-args is the same.
|
||||||
|
(if never-wrapped?
|
||||||
|
(super-go the-obj si_c si_inited? init-args null null)
|
||||||
|
(init the-obj super-go si_c si_inited? init-args init-args))))))
|
||||||
|
|
||||||
;; For augment and augride contracts, we both update the projection
|
c))))
|
||||||
;; and go ahead and apply the projection to the last slot (which will
|
|
||||||
;; only be used by later classes).
|
|
||||||
(unless (and (null? (class/c-augments ctc))
|
|
||||||
(null? (class/c-augrides ctc)))
|
|
||||||
(for ([m (in-list (append (class/c-augments ctc)
|
|
||||||
(class/c-augrides ctc)))]
|
|
||||||
[c (in-list (append (class/c-augment-contracts ctc)
|
|
||||||
(class/c-augride-contracts ctc)))])
|
|
||||||
(when c
|
|
||||||
(let* ([i (hash-ref method-ht m)]
|
|
||||||
[p ((contract-projection c) (blame-add-method-context blame i))]
|
|
||||||
[old-idx (vector-ref old-idxs i)]
|
|
||||||
[new-idx (vector-ref dynamic-idxs i)]
|
|
||||||
[proj-vec (vector-ref dynamic-projs i)]
|
|
||||||
[int-vec (vector-ref int-methods i)]
|
|
||||||
[old-proj (vector-ref proj-vec old-idx)])
|
|
||||||
(vector-set! proj-vec old-idx (λ (v) (p (old-proj v))))
|
|
||||||
(vector-set! int-vec new-idx
|
|
||||||
(make-method (p (vector-ref int-vec new-idx)) m))))))
|
|
||||||
|
|
||||||
;; Now (that things have been extended appropriately) we handle
|
(define (blame-add-method-context blame thing)
|
||||||
;; inherits.
|
|
||||||
(unless (null? (class/c-inherits ctc))
|
|
||||||
(for ([m (in-list (class/c-inherits ctc))]
|
|
||||||
[c (in-list (class/c-inherit-contracts ctc))])
|
|
||||||
(when c
|
|
||||||
(let* ([i (hash-ref method-ht m)]
|
|
||||||
[p ((contract-projection c) (blame-add-method-context blame i))]
|
|
||||||
[new-idx (vector-ref dynamic-idxs i)]
|
|
||||||
[int-vec (vector-ref int-methods i)])
|
|
||||||
(vector-set! int-vec new-idx
|
|
||||||
(make-method (p (vector-ref int-vec new-idx)) m)))))))
|
|
||||||
|
|
||||||
;; Unlike the others, we always want to do this, even if there are no init contracts,
|
|
||||||
;; since we still need to handle either calling the previous class/c's init or
|
|
||||||
;; calling continue-make-super appropriately.
|
|
||||||
(let ()
|
|
||||||
;; zip the inits and contracts together for ordered selection
|
|
||||||
(define inits+contracts (map cons (class/c-inits ctc) (class/c-init-contracts ctc)))
|
|
||||||
;; grab all the inits+contracts that involve the same init arg
|
|
||||||
;; (assumes that inits and contracts were sorted in class/c creation)
|
|
||||||
(define (grab-same-inits lst)
|
|
||||||
(if (null? lst)
|
|
||||||
(values null null)
|
|
||||||
(let loop ([inits/c (cdr lst)]
|
|
||||||
[prefix (list (car lst))])
|
|
||||||
(cond
|
|
||||||
[(null? inits/c)
|
|
||||||
(values (reverse prefix) inits/c)]
|
|
||||||
[(eq? (car (car inits/c)) (car (car prefix)))
|
|
||||||
(loop (cdr inits/c)
|
|
||||||
(cons (car inits/c) prefix))]
|
|
||||||
[else (values (reverse prefix) inits/c)]))))
|
|
||||||
;; run through the list of init-args and apply contracts for same-named
|
|
||||||
;; init args
|
|
||||||
(define (apply-contracts inits/c init-args)
|
|
||||||
(let loop ([init-args init-args]
|
|
||||||
[inits/c inits/c]
|
|
||||||
[handled-args null])
|
|
||||||
(cond
|
|
||||||
[(null? init-args)
|
|
||||||
(reverse handled-args)]
|
|
||||||
[(null? inits/c)
|
|
||||||
(append (reverse handled-args) init-args)]
|
|
||||||
[(eq? (car (car inits/c)) (car (car init-args)))
|
|
||||||
(let ([init-arg (car init-args)]
|
|
||||||
[p ((contract-projection (cdr (car inits/c))) bswap)])
|
|
||||||
(loop (cdr init-args)
|
|
||||||
(cdr inits/c)
|
|
||||||
(cons (cons (car init-arg) (p (cdr init-arg)))
|
|
||||||
handled-args)))]
|
|
||||||
[else (loop (cdr init-args)
|
|
||||||
inits/c
|
|
||||||
(cons (car init-args) handled-args))])))
|
|
||||||
(set-class-init!
|
|
||||||
c
|
|
||||||
(lambda (the-obj super-go si_c si_inited? si_leftovers init-args)
|
|
||||||
(let ([init-args
|
|
||||||
(let loop ([inits/c inits+contracts]
|
|
||||||
[handled-args init-args])
|
|
||||||
(if (null? inits/c)
|
|
||||||
handled-args
|
|
||||||
(let-values ([(prefix suffix) (grab-same-inits inits/c)])
|
|
||||||
(loop suffix
|
|
||||||
(apply-contracts prefix init-args)))))])
|
|
||||||
;; Since we never consume init args, we can ignore si_leftovers
|
|
||||||
;; since init-args is the same.
|
|
||||||
(if never-wrapped?
|
|
||||||
(super-go the-obj si_c si_inited? init-args null null)
|
|
||||||
(init the-obj super-go si_c si_inited? init-args init-args))))))
|
|
||||||
|
|
||||||
c)))))
|
|
||||||
|
|
||||||
(define (blame-add-method-context blame method-proc)
|
|
||||||
(define name (object-name method-proc))
|
|
||||||
(cond
|
(cond
|
||||||
[name
|
[(and (procedure? thing)
|
||||||
|
(object-name thing))
|
||||||
|
(define name (object-name thing))
|
||||||
;; the procedure name of a method has ' method in ...' in it; trim that away
|
;; the procedure name of a method has ' method in ...' in it; trim that away
|
||||||
(define method-name (regexp-replace #rx" method in .*%.?$" (symbol->string name) ""))
|
(define method-name (regexp-replace #rx" method in .*%.?$" (symbol->string name) ""))
|
||||||
(blame-add-context blame
|
(blame-add-context blame
|
||||||
(format "the ~a method in" method-name)
|
(format "the ~a method in" method-name)
|
||||||
#:important
|
#:important
|
||||||
name)]
|
name)]
|
||||||
|
[(symbol? thing)
|
||||||
|
;; the procedure name of a method has ' method in ...' in it; trim that away
|
||||||
|
(blame-add-context blame
|
||||||
|
(format "the ~a method in" thing)
|
||||||
|
#:important
|
||||||
|
thing)]
|
||||||
[else
|
[else
|
||||||
(blame-add-context blame "an unnamed method in")]))
|
(blame-add-context blame "an unnamed method in")]))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user