Avoid a parameter for controlling resolve caching
The parameter dereference slowed down type-checking new-metrics.rkt to about 28s from 16s on DrDr. Instead of the parameter, explicitly remove items from the cache during type alias setup.
This commit is contained in:
parent
e4716bd68a
commit
862d58a2f4
|
@ -101,166 +101,171 @@
|
||||||
;; other definitions need to be registered, do that before calling
|
;; other definitions need to be registered, do that before calling
|
||||||
;; this function.
|
;; this function.
|
||||||
(define (register-all-type-aliases type-alias-names type-alias-map)
|
(define (register-all-type-aliases type-alias-names type-alias-map)
|
||||||
;; Disable resolve caching for the extent of this setup.
|
;; Find type alias dependencies
|
||||||
;; Makes sure Name types don't get cached too soon.
|
;; The two maps defined here contains the dependency structure
|
||||||
(parameterize ([current-cache-resolve? #f])
|
;; of type aliases in two senses:
|
||||||
;; Find type alias dependencies
|
;; (1) other type aliases referenced in a type alias
|
||||||
;; The two maps defined here contains the dependency structure
|
;; (2) other type aliases referenced by some class in a
|
||||||
;; of type aliases in two senses:
|
;; type alias in a #:implements clause
|
||||||
;; (1) other type aliases referenced in a type alias
|
;;
|
||||||
;; (2) other type aliases referenced by some class in a
|
;; The second is necessary in order to prevent recursive
|
||||||
;; type alias in a #:implements clause
|
;; #:implements clauses and to determine the order in which
|
||||||
;;
|
;; recursive type aliases should be initialized.
|
||||||
;; The second is necessary in order to prevent recursive
|
(define-values (type-alias-dependency-map type-alias-class-map)
|
||||||
;; #:implements clauses and to determine the order in which
|
(for/lists (_1 _2)
|
||||||
;; recursive type aliases should be initialized.
|
([(name alias-info) (in-dict type-alias-map)])
|
||||||
(define-values (type-alias-dependency-map type-alias-class-map)
|
(define links-box (box null))
|
||||||
(for/lists (_1 _2)
|
(define class-box (box null))
|
||||||
([(name alias-info) (in-dict type-alias-map)])
|
(define type
|
||||||
(define links-box (box null))
|
(parameterize ([current-type-alias-name name]
|
||||||
(define class-box (box null))
|
[current-referenced-aliases links-box]
|
||||||
(define type
|
[current-referenced-class-parents class-box])
|
||||||
(parameterize ([current-type-alias-name name]
|
(parse-type (car alias-info))))
|
||||||
[current-referenced-aliases links-box]
|
(define pre-dependencies
|
||||||
[current-referenced-class-parents class-box])
|
(remove-duplicates (unbox links-box) free-identifier=?))
|
||||||
(parse-type (car alias-info))))
|
(define (filter-by-type-alias-names names)
|
||||||
(define pre-dependencies
|
(for/list ([id (in-list names)]
|
||||||
(remove-duplicates (unbox links-box) free-identifier=?))
|
#:when (memf (λ (id2) (free-identifier=? id id2))
|
||||||
(define (filter-by-type-alias-names names)
|
type-alias-names))
|
||||||
(for/list ([id (in-list names)]
|
id))
|
||||||
#:when (memf (λ (id2) (free-identifier=? id id2))
|
(define alias-dependencies
|
||||||
type-alias-names))
|
(filter-by-type-alias-names pre-dependencies))
|
||||||
id))
|
(define class-dependencies
|
||||||
(define alias-dependencies
|
(filter-by-type-alias-names (unbox class-box)))
|
||||||
(filter-by-type-alias-names pre-dependencies))
|
(values (cons name alias-dependencies)
|
||||||
(define class-dependencies
|
(cons name class-dependencies))))
|
||||||
(filter-by-type-alias-names (unbox class-box)))
|
|
||||||
(values (cons name alias-dependencies)
|
|
||||||
(cons name class-dependencies))))
|
|
||||||
|
|
||||||
(define components
|
(define components
|
||||||
(find-strongly-connected-type-aliases type-alias-dependency-map))
|
(find-strongly-connected-type-aliases type-alias-dependency-map))
|
||||||
|
|
||||||
(define class-components
|
(define class-components
|
||||||
(find-strongly-connected-type-aliases type-alias-class-map))
|
(find-strongly-connected-type-aliases type-alias-class-map))
|
||||||
|
|
||||||
;; helper function for defining singletons
|
;; helper function for defining singletons
|
||||||
(define (has-self-cycle? component [map type-alias-dependency-map])
|
(define (has-self-cycle? component [map type-alias-dependency-map])
|
||||||
(define id (car component))
|
(define id (car component))
|
||||||
(memf (λ (id2) (free-identifier=? id id2))
|
(memf (λ (id2) (free-identifier=? id id2))
|
||||||
(dict-ref map id)))
|
(dict-ref map id)))
|
||||||
|
|
||||||
;; A singleton component can be either a self-cycle or a node that
|
;; A singleton component can be either a self-cycle or a node that
|
||||||
;; that does not participate in cycles, so we disambiguate
|
;; that does not participate in cycles, so we disambiguate
|
||||||
(define-values (acyclic-singletons recursive-aliases)
|
(define-values (acyclic-singletons recursive-aliases)
|
||||||
(for/fold ([singletons '()] [other '()])
|
(for/fold ([singletons '()] [other '()])
|
||||||
([component (in-list components)])
|
([component (in-list components)])
|
||||||
(if (and (= (length component) 1)
|
(if (and (= (length component) 1)
|
||||||
(not (has-self-cycle? component)))
|
(not (has-self-cycle? component)))
|
||||||
(values (cons (car component) singletons) other)
|
(values (cons (car component) singletons) other)
|
||||||
(values singletons (append component other)))))
|
(values singletons (append component other)))))
|
||||||
|
|
||||||
;; Check that no #:implements clauses are recursive
|
;; Check that no #:implements clauses are recursive
|
||||||
(define counterexample
|
(define counterexample
|
||||||
(for/or ([component class-components])
|
(for/or ([component class-components])
|
||||||
(and (or (not (= (length component) 1))
|
(and (or (not (= (length component) 1))
|
||||||
(has-self-cycle? component type-alias-class-map))
|
(has-self-cycle? component type-alias-class-map))
|
||||||
component)))
|
component)))
|
||||||
(when counterexample
|
(when counterexample
|
||||||
(tc-error/stx
|
(tc-error/stx
|
||||||
(car counterexample)
|
(car counterexample)
|
||||||
"Recursive #:implements clause not allowed"))
|
"Recursive #:implements clause not allowed"))
|
||||||
|
|
||||||
;; Split recursive aliases into those involving classes
|
;; Split recursive aliases into those involving classes
|
||||||
;; (in reverse topological order) and the rest of the aliases
|
;; (in reverse topological order) and the rest of the aliases
|
||||||
(define class-aliases
|
(define class-aliases
|
||||||
(for/list ([component (in-list (reverse class-components))]
|
(for/list ([component (in-list (reverse class-components))]
|
||||||
#:when (member (car component)
|
#:when (member (car component)
|
||||||
recursive-aliases
|
recursive-aliases
|
||||||
|
free-identifier=?))
|
||||||
|
(car component)))
|
||||||
|
(define other-recursive-aliases
|
||||||
|
(for/list ([alias (in-list recursive-aliases)]
|
||||||
|
#:unless (member alias
|
||||||
|
class-aliases
|
||||||
free-identifier=?))
|
free-identifier=?))
|
||||||
(car component)))
|
alias))
|
||||||
(define other-recursive-aliases
|
|
||||||
(for/list ([alias (in-list recursive-aliases)]
|
;; Reconstruct type alias dependency map based on class parent
|
||||||
#:unless (member alias
|
;; information. This ensures that the `deps` field is precise
|
||||||
class-aliases
|
;; in all type aliases involving class types
|
||||||
|
(define (get-all-parent-deps id)
|
||||||
|
(define (get-deps parent)
|
||||||
|
(cdr (assoc parent type-alias-dependency-map free-identifier=?)))
|
||||||
|
(define parents (cdr (assoc id type-alias-class-map free-identifier=?)))
|
||||||
|
(cond [(null? parents) null]
|
||||||
|
[else
|
||||||
|
(define all-deps
|
||||||
|
(for/list ([parent parents])
|
||||||
|
(append (get-deps parent)
|
||||||
|
(get-all-parent-deps parent))))
|
||||||
|
(apply append all-deps)]))
|
||||||
|
|
||||||
|
(define new-dependency-map/classes
|
||||||
|
(for/list ([(id deps) (in-dict type-alias-dependency-map)])
|
||||||
|
(cond [(dict-has-key? type-alias-class-map id)
|
||||||
|
(define new-deps
|
||||||
|
(remove-duplicates (append (get-all-parent-deps id) deps)
|
||||||
free-identifier=?))
|
free-identifier=?))
|
||||||
alias))
|
(cons id new-deps)]
|
||||||
|
[else (cons id deps)])))
|
||||||
|
|
||||||
;; Reconstruct type alias dependency map based on class parent
|
;; Do another pass on dependency map, using the connected
|
||||||
;; information. This ensures that the `deps` field is precise
|
;; components analysis data to determine which dependencies are
|
||||||
;; in all type aliases involving class types
|
;; actually needed for mutual recursion. Drop all others.
|
||||||
(define (get-all-parent-deps id)
|
(define new-dependency-map
|
||||||
(define (get-deps parent)
|
(for/list ([(id deps) (in-dict new-dependency-map/classes)])
|
||||||
(cdr (assoc parent type-alias-dependency-map free-identifier=?)))
|
;; find the component this `id` participated in so
|
||||||
(define parents (cdr (assoc id type-alias-class-map free-identifier=?)))
|
;; that we can drop `deps` that aren't in that component
|
||||||
(cond [(null? parents) null]
|
(define component
|
||||||
[else
|
(findf (λ (component) (member id component free-identifier=?))
|
||||||
(define all-deps
|
components))
|
||||||
(for/list ([parent parents])
|
(define new-deps
|
||||||
(append (get-deps parent)
|
(filter (λ (dep) (member dep component free-identifier=?)) deps))
|
||||||
(get-all-parent-deps parent))))
|
(cons id new-deps)))
|
||||||
(apply append all-deps)]))
|
|
||||||
|
|
||||||
(define new-dependency-map/classes
|
;; Actually register recursive type aliases
|
||||||
(for/list ([(id deps) (in-dict type-alias-dependency-map)])
|
(define name-types
|
||||||
(cond [(dict-has-key? type-alias-class-map id)
|
(for/list ([id (in-list recursive-aliases)])
|
||||||
(define new-deps
|
|
||||||
(remove-duplicates (append (get-all-parent-deps id) deps)
|
|
||||||
free-identifier=?))
|
|
||||||
(cons id new-deps)]
|
|
||||||
[else (cons id deps)])))
|
|
||||||
|
|
||||||
;; Do another pass on dependency map, using the connected
|
|
||||||
;; components analysis data to determine which dependencies are
|
|
||||||
;; actually needed for mutual recursion. Drop all others.
|
|
||||||
(define new-dependency-map
|
|
||||||
(for/list ([(id deps) (in-dict new-dependency-map/classes)])
|
|
||||||
;; find the component this `id` participated in so
|
|
||||||
;; that we can drop `deps` that aren't in that component
|
|
||||||
(define component
|
|
||||||
(findf (λ (component) (member id component free-identifier=?))
|
|
||||||
components))
|
|
||||||
(define new-deps
|
|
||||||
(filter (λ (dep) (member dep component free-identifier=?)) deps))
|
|
||||||
(cons id new-deps)))
|
|
||||||
|
|
||||||
;; Actually register recursive type aliases
|
|
||||||
(for ([id (in-list recursive-aliases)])
|
|
||||||
(define record (dict-ref type-alias-map id))
|
(define record (dict-ref type-alias-map id))
|
||||||
(match-define (list _ args) record)
|
(match-define (list _ args) record)
|
||||||
(define deps (dict-ref new-dependency-map id))
|
(define deps (dict-ref new-dependency-map id))
|
||||||
(register-resolved-type-alias id (make-Name id deps args #f)))
|
(define name-type (make-Name id deps args #f))
|
||||||
|
(register-resolved-type-alias id name-type)
|
||||||
|
name-type))
|
||||||
|
|
||||||
;; Register non-recursive type aliases
|
;; Register non-recursive type aliases
|
||||||
;;
|
;;
|
||||||
;; Note that the connected component algorithm returns results
|
;; Note that the connected component algorithm returns results
|
||||||
;; in topologically sorted order, so we want to go through in the
|
;; in topologically sorted order, so we want to go through in the
|
||||||
;; reverse order of that to avoid unbound type aliases.
|
;; reverse order of that to avoid unbound type aliases.
|
||||||
(for ([id (in-list acyclic-singletons)])
|
(for ([id (in-list acyclic-singletons)])
|
||||||
(define type-stx (car (dict-ref type-alias-map id)))
|
(define type-stx (car (dict-ref type-alias-map id)))
|
||||||
(register-resolved-type-alias id (parse-type type-stx)))
|
(register-resolved-type-alias id (parse-type type-stx)))
|
||||||
|
|
||||||
;; Finish registering recursive aliases
|
;; Clear the resolver cache of Name types from this block
|
||||||
;; names-to-refine : Listof<Id>
|
(define (reset-resolver-cache!) (resolver-cache-remove! name-types))
|
||||||
;; types-to-refine : Listof<Type>
|
(reset-resolver-cache!)
|
||||||
;; tvarss : Listof<Listof<Symbol>>
|
|
||||||
(define-values (names-to-refine types-to-refine tvarss)
|
|
||||||
(for/lists (_1 _2 _3)
|
|
||||||
([id (in-list (append other-recursive-aliases class-aliases))])
|
|
||||||
(define record (dict-ref type-alias-map id))
|
|
||||||
(match-define (list type-stx args) record)
|
|
||||||
(define type
|
|
||||||
;; make sure to reject the type if it uses polymorphic
|
|
||||||
;; recursion (see resolve.rkt)
|
|
||||||
(parameterize ([current-check-polymorphic-recursion args])
|
|
||||||
(parse-type type-stx)))
|
|
||||||
(register-type-name id type)
|
|
||||||
(add-constant-variance! id args)
|
|
||||||
(check-type-alias-contractive id type)
|
|
||||||
(values id type args)))
|
|
||||||
|
|
||||||
;; Finally, do a last pass to refine the variance
|
;; Finish registering recursive aliases
|
||||||
(refine-variance! names-to-refine types-to-refine tvarss)))
|
;; names-to-refine : Listof<Id>
|
||||||
|
;; types-to-refine : Listof<Type>
|
||||||
|
;; tvarss : Listof<Listof<Symbol>>
|
||||||
|
(define-values (names-to-refine types-to-refine tvarss)
|
||||||
|
(for/lists (_1 _2 _3)
|
||||||
|
([id (in-list (append other-recursive-aliases class-aliases))])
|
||||||
|
(define record (dict-ref type-alias-map id))
|
||||||
|
(match-define (list type-stx args) record)
|
||||||
|
(define type
|
||||||
|
;; make sure to reject the type if it uses polymorphic
|
||||||
|
;; recursion (see resolve.rkt)
|
||||||
|
(parameterize ([current-check-polymorphic-recursion args])
|
||||||
|
(parse-type type-stx)))
|
||||||
|
(reset-resolver-cache!)
|
||||||
|
(register-type-name id type)
|
||||||
|
(add-constant-variance! id args)
|
||||||
|
(check-type-alias-contractive id type)
|
||||||
|
(values id type args)))
|
||||||
|
|
||||||
|
;; Finally, do a last pass to refine the variance
|
||||||
|
(refine-variance! names-to-refine types-to-refine tvarss))
|
||||||
|
|
||||||
;; Syntax -> Syntax Syntax Syntax Option<Integer>
|
;; Syntax -> Syntax Syntax Syntax Option<Integer>
|
||||||
;; Parse a type alias internal declaration
|
;; Parse a type alias internal declaration
|
||||||
|
|
|
@ -11,19 +11,12 @@
|
||||||
|
|
||||||
(provide resolve-name resolve-app needs-resolving?
|
(provide resolve-name resolve-app needs-resolving?
|
||||||
resolve resolve-app-check-error
|
resolve resolve-app-check-error
|
||||||
current-cache-resolve?
|
resolver-cache-remove!
|
||||||
current-check-polymorphic-recursion)
|
current-check-polymorphic-recursion)
|
||||||
(provide/cond-contract [resolve-once (Type/c . -> . (or/c Type/c #f))])
|
(provide/cond-contract [resolve-once (Type/c . -> . (or/c Type/c #f))])
|
||||||
|
|
||||||
(define-struct poly (name vars) #:prefab)
|
(define-struct poly (name vars) #:prefab)
|
||||||
|
|
||||||
;; This parameter allows other parts of the typechecker to
|
|
||||||
;; request that the resolve cache isn't updated. This is needed
|
|
||||||
;; by the setup for recursive type aliases, since certain Name
|
|
||||||
;; types should not be cached while their mapping is still being
|
|
||||||
;; computed.
|
|
||||||
(define current-cache-resolve? (make-parameter #f))
|
|
||||||
|
|
||||||
;; Parameter<Option<Listof<Symbol>>>
|
;; Parameter<Option<Listof<Symbol>>>
|
||||||
;; This parameter controls whether or not the resolving process
|
;; This parameter controls whether or not the resolving process
|
||||||
;; should check for polymorphic recursion in implicit recursive
|
;; should check for polymorphic recursion in implicit recursive
|
||||||
|
@ -146,11 +139,17 @@
|
||||||
(resolve-app r r* s)]
|
(resolve-app r r* s)]
|
||||||
[(Name: _ _ _ _) (resolve-name t)])])
|
[(Name: _ _ _ _) (resolve-name t)])])
|
||||||
(when (and r*
|
(when (and r*
|
||||||
(not (currently-subtyping?))
|
(not (currently-subtyping?)))
|
||||||
(current-cache-resolve?))
|
|
||||||
(hash-set! resolver-cache seq r*))
|
(hash-set! resolver-cache seq r*))
|
||||||
r*)))
|
r*)))
|
||||||
|
|
||||||
|
;; resolver-cache-remove! : (Listof Type) -> Void
|
||||||
|
;; Removes the given types from the resolver cache. This is
|
||||||
|
;; only used by recursive type alias set-up, which sometimes needs to
|
||||||
|
;; undo certain resolutions.
|
||||||
|
(define (resolver-cache-remove! keys)
|
||||||
|
(for ([key (in-list keys)])
|
||||||
|
(hash-remove! resolver-cache (Rep-seq key))))
|
||||||
|
|
||||||
;; Repeatedly unfolds Mu, App, and Name constructors until the top type
|
;; Repeatedly unfolds Mu, App, and Name constructors until the top type
|
||||||
;; constructor is not one of them.
|
;; constructor is not one of them.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user