Make subtyping checks on objects faster

This commit is contained in:
Asumu Takikawa 2013-08-22 12:12:36 -04:00
parent e80c4d72fb
commit c8e5423e55
2 changed files with 62 additions and 39 deletions

View File

@ -26,13 +26,14 @@
Values/c SomeValues/c Values/c SomeValues/c
Poly-n Poly-n
PolyDots-n PolyDots-n
Class? Class? Row? Row:
free-vars* free-vars*
type-compare type<? type-compare type<?
remove-dups remove-dups
sub-f sub-o sub-pe sub-f sub-o sub-pe
(rename-out [Class:* Class:] (rename-out [Class:* Class:]
[Class* make-Class] [Class* make-Class]
[Row* make-Row]
[Mu:* Mu:] [Mu:* Mu:]
[Poly:* Poly:] [Poly:* Poly:]
[PolyDots:* PolyDots:] [PolyDots:* PolyDots:]
@ -457,11 +458,15 @@
;; A Row used in type instantiation ;; A Row used in type instantiation
;; For now, this should not appear in user code. It's used ;; For now, this should not appear in user code. It's used
;; internally to perform row instantiations ;; internally to perform row instantiations and to represent
;; class types.
;;
;; invariant: all clauses are sorted by the key name
(def-type Row ([inits (listof (list/c symbol? Type/c boolean?))] (def-type Row ([inits (listof (list/c symbol? Type/c boolean?))]
[fields (listof (list/c symbol? Type/c))] [fields (listof (list/c symbol? Type/c))]
[methods (listof (list/c symbol? Function?))] [methods (listof (list/c symbol? Function?))]
[augments (listof (list/c symbol? Function?))]) [augments (listof (list/c symbol? Function?))])
#:no-provide
[#:frees (λ (f) (combine-frees [#:frees (λ (f) (combine-frees
(map f (append (map cadr inits) (map f (append (map cadr inits)
(map cadr fields) (map cadr fields)
@ -904,6 +909,15 @@
(PolyRow-body* fresh-syms t))) (PolyRow-body* fresh-syms t)))
(list nps freshp constrp bp)))]))) (list nps freshp constrp bp)))])))
;; Row*
;; This is a custom constructor for Row types
;; Sorts all clauses by the key (the clause name)
(define (Row* inits fields methods augments)
(*Row (sort-row-clauses inits)
(sort-row-clauses fields)
(sort-row-clauses methods)
(sort-row-clauses augments)))
;; Class* ;; Class*
;; This is a custom constructor for Class types that ;; This is a custom constructor for Class types that
;; doesn't require writing make-Row everywhere ;; doesn't require writing make-Row everywhere
@ -914,7 +928,7 @@
(listof (list/c symbol? Function?)) (listof (list/c symbol? Function?))
(listof (list/c symbol? Function?)) (listof (list/c symbol? Function?))
Class?) Class?)
(*Class row-var (*Row inits fields methods augments))) (*Class row-var (Row* inits fields methods augments)))
;; Class:* ;; Class:*
;; This match expander replaces the built-in matching with ;; This match expander replaces the built-in matching with
@ -936,12 +950,19 @@
(define row-methods (Row-methods row)) (define row-methods (Row-methods row))
(define row-augments (Row-augments row)) (define row-augments (Row-augments row))
(list row (list row
(append inits row-inits) ;; FIXME: instead of sorting here every time
(append fields row-fields) ;; the match expander is called, the row
(append methods row-methods) ;; fields should be merged on substitution
(append augments row-augments))] (sort-row-clauses (append inits row-inits))
(sort-row-clauses (append fields row-fields))
(sort-row-clauses (append methods row-methods))
(sort-row-clauses (append augments row-augments)))]
[else (list row inits fields methods augments)])) [else (list row inits fields methods augments)]))
;; sorts the given field of a Row by the member name
(define (sort-row-clauses clauses)
(sort clauses symbol<? #:key car))
(define-match-expander Class:* (define-match-expander Class:*
(λ (stx) (λ (stx)
(syntax-case stx () (syntax-case stx ()

View File

@ -580,17 +580,24 @@
[((Instance: (Class: _ _ field-map method-map augment-map)) [((Instance: (Class: _ _ field-map method-map augment-map))
(Instance: (Class: _ _ field-map* method-map* augment-map*))) (Instance: (Class: _ _ field-map* method-map* augment-map*)))
(define (subtype-clause? map map*) (define (subtype-clause? map map*)
(match-define (list (and s (list names types)) ...) map) ;; invariant: map and map* are sorted by key
(match-define (list (and s* (list names* types*)) ...) map*) (let loop ([A A0] [map map] [map* map*])
(for/fold ([A A0]) (cond [(or (empty? map) (empty? map*)) #t]
([n names*] [m types*] #:break (not A)) [else
(and A (cond [(assq n s) => (match-define (list name type) (car map))
(lambda (spec) (subtype* A (cadr spec) m))] (match-define (list name* type*) (car map*))
[else #f])))) (cond [;; quit if 2nd obj lacks a name in 1st obj
(and ;; Note that augment/public doesn't matter for object (symbol<? name* name)
;; subtyping, so these mappings can be merged #f]
(subtype-clause? (append method-map augment-map) [;; if 1st obj lacks a name in 2nd obj, try
(append method-map* augment-map*)) ;; the next one
(symbol<? name name*)
(loop A (cdr map) map*)]
[else
(define A* (subtype* A type type*))
(and A* (loop A* (cdr map) (cdr map*)))])])))
(and ;; Note that init & augment clauses don't matter for objects
(subtype-clause? method-map method-map*)
(subtype-clause? field-map field-map*))] (subtype-clause? field-map field-map*))]
[((Class: row inits fields methods augments) [((Class: row inits fields methods augments)
(Class: row* inits* fields* methods* augments*)) (Class: row* inits* fields* methods* augments*))
@ -599,10 +606,6 @@
;; check that each of inits, fields, methods, etc. are ;; check that each of inits, fields, methods, etc. are
;; equal by sorting and checking type equality ;; equal by sorting and checking type equality
(define (equal-clause? clause clause* [inits? #f]) (define (equal-clause? clause clause* [inits? #f])
(define (sort-clause lst)
(sort lst string<? #:key (compose symbol->string car)))
(let ([clause (sort-clause clause)]
[clause* (sort-clause clause*)])
(cond (cond
[(not inits?) [(not inits?)
(match-define (list (list names types) ...) clause) (match-define (list (list names types) ...) clause)
@ -618,7 +621,7 @@
(and (= (length names) (length names*)) (and (= (length names) (length names*))
(andmap equal? names names*) (andmap equal? names names*)
(andmap sub types types*) (andmap sub types types*)
(andmap equal? opt? opt?*))]))) (andmap equal? opt? opt?*))]))
;; There is no non-trivial width subtyping on class types, but it's ;; There is no non-trivial width subtyping on class types, but it's
;; possible for two "equal" class types to look different ;; possible for two "equal" class types to look different
;; in the representation. We deal with that here. ;; in the representation. We deal with that here.
@ -627,7 +630,6 @@
(equal? row row*)) (equal? row row*))
(equal-clause? inits inits* #t) (equal-clause? inits inits* #t)
(equal-clause? fields fields*) (equal-clause? fields fields*)
;; augment/public distinction is important here
(equal-clause? methods methods*) (equal-clause? methods methods*)
(equal-clause? augments augments*))] (equal-clause? augments augments*))]
;; otherwise, not a subtype ;; otherwise, not a subtype