Implement substitutions as hash tables from vars to subst-rhs.

- add convenience function for generating substitutions
 - give trivial substitution for unreferenced index variables
This commit is contained in:
Sam Tobin-Hochstadt 2010-06-18 15:14:42 -04:00
parent 6b12757506
commit 339add9f78
6 changed files with 72 additions and 54 deletions

View File

@ -14,7 +14,7 @@
scheme/match scheme/match
mzlib/etc mzlib/etc
mzlib/trace racket/contract mzlib/trace racket/contract
unstable/sequence unstable/list unstable/debug unstable/sequence unstable/list unstable/debug unstable/hash
scheme/list) scheme/list)
(import dmap^ constraints^ promote-demote^) (import dmap^ constraints^ promote-demote^)
@ -478,7 +478,7 @@
;; Y : (listof symbol?) - index variables that must have entries ;; Y : (listof symbol?) - index variables that must have entries
;; R : Type? - result type into which we will be substituting ;; R : Type? - result type into which we will be substituting
(d/c (subst-gen C Y R) (d/c (subst-gen C Y R)
(cset? (listof symbol?) Type? . -> . (or/c #f list?)) (cset? (listof symbol?) Type? . -> . (or/c #f substitution/c))
(define var-hash (free-vars* R)) (define var-hash (free-vars* R))
(define idx-hash (free-idxs* R)) (define idx-hash (free-idxs* R))
;; v : Symbol - variable for which to check variance ;; v : Symbol - variable for which to check variance
@ -499,11 +499,20 @@
;; was found. If we're at this point and had no other constraints, then adding the ;; was found. If we're at this point and had no other constraints, then adding the
;; equivalent of the constraint (dcon null (c Bot X Top)) is okay. ;; equivalent of the constraint (dcon null (c Bot X Top)) is okay.
(define (extend-idxs S) (define (extend-idxs S)
(define fi-R (fi R))
;; If the index variable v is not used in the type, then
;; we allow it to be replaced with the empty list of types;
;; otherwise we error, as we do not yet know what an appropriate
;; lower bound is.
(define (demote/check-free v)
(if (memq v fi-R)
(int-err "attempted to demote dotted variable")
(i-subst null)))
;; absent-entries is #f if there's an error in the substitution, otherwise ;; absent-entries is #f if there's an error in the substitution, otherwise
;; it's a list of variables that don't appear in the substitution ;; it's a list of variables that don't appear in the substitution
(define absent-entries (define absent-entries
(for/fold ([no-entry null]) ([v (in-list Y)]) (for/fold ([no-entry null]) ([v (in-list Y)])
(let ([entry (assq v S)]) (let ([entry (hash-ref S v #f)])
;; Make sure we got a subst entry for an index var ;; Make sure we got a subst entry for an index var
;; (i.e. a list of types for the fixed portion ;; (i.e. a list of types for the fixed portion
;; and a type for the starred portion) ;; and a type for the starred portion)
@ -513,40 +522,42 @@
[(or (i-subst? entry) (i-subst/starred? entry) (i-subst/dotted? entry)) no-entry] [(or (i-subst? entry) (i-subst/starred? entry) (i-subst/dotted? entry)) no-entry]
[else #f])))) [else #f]))))
(and absent-entries (and absent-entries
(append (hash-union
(for/list ([missing (in-list absent-entries)]) (for/hash ([missing (in-list absent-entries)])
(let ([var (hash-ref idx-hash missing Constant)]) (let ([var (hash-ref idx-hash missing Constant)])
(evcase var (values missing
[Constant (int-err "attempted to demote dotted variable")] (evcase var
[Covariant (int-err "attempted to demote dotted variable")] [Constant (demote/check-free missing)]
[Contravariant (i-subst/starred missing null Univ)] [Covariant (demote/check-free missing)]
[Invariant (int-err "attempted to demote dotted variable")]))) [Contravariant (i-subst/starred null Univ)]
[Invariant (demote/check-free missing)]))))
S))) S)))
(match (car (cset-maps C)) (match (car (cset-maps C))
[(cons cmap (dmap dm)) [(cons cmap (dmap dm))
(let ([subst (append (let ([subst (hash-union
(for/list ([(k dc) (in-hash dm)]) (for/hash ([(k dc) (in-hash dm)])
(match dc (match dc
[(dcon fixed #f) [(dcon fixed #f)
(i-subst k (values k
(i-subst
(for/list ([f fixed]) (for/list ([f fixed])
(constraint->type f idx-hash #:variable k)))] (constraint->type f idx-hash #:variable k))))]
[(dcon fixed rest) [(dcon fixed rest)
(i-subst/starred k (values k
(for/list ([f fixed]) (i-subst/starred (for/list ([f fixed])
(constraint->type f idx-hash #:variable k)) (constraint->type f idx-hash #:variable k))
(constraint->type rest idx-hash))] (constraint->type rest idx-hash)))]
[(dcon-exact fixed rest) [(dcon-exact fixed rest)
(i-subst/starred (values k
k (i-subst/starred
(for/list ([f fixed]) (for/list ([f fixed])
(constraint->type f idx-hash #:variable k)) (constraint->type f idx-hash #:variable k))
(constraint->type rest idx-hash))])) (constraint->type rest idx-hash)))]))
(for/list ([(k v) (in-hash cmap)]) (for/hash ([(k v) (in-hash cmap)])
(t-subst k (constraint->type v var-hash))))]) (values k (t-subst (constraint->type v var-hash)))))])
;; verify that we got all the important variables ;; verify that we got all the important variables
(and (for/and ([v (fv R)]) (and (for/and ([v (fv R)])
(let ([entry (assq v subst)]) (let ([entry (hash-ref subst v #f)])
;; Make sure we got a subst entry for a type var ;; Make sure we got a subst entry for a type var
;; (i.e. just a type to substitute) ;; (i.e. just a type to substitute)
(and entry (t-subst? entry)))) (and entry (t-subst? entry))))

View File

@ -360,6 +360,7 @@
(values tail-ty tail-bound)] (values tail-ty tail-bound)]
[t (values t #f)])]) [t (values t #f)])])
(let loop ([doms* doms] [rngs* rngs] [rests* rests] [drests* drests]) (let loop ([doms* doms] [rngs* rngs] [rests* rests] [drests* drests])
(define (finish substitution) (do-ret (subst-all substitution (car rngs*))))
(cond [(null? doms*) (cond [(null? doms*)
(match f-ty (match f-ty
[(tc-result1: (PolyDots-names: _ (Function: (list (arr: doms rngs rests drests (list (Keyword: _ _ #f) ...)) ..1)))) [(tc-result1: (PolyDots-names: _ (Function: (list (arr: doms rngs rests drests (list (Keyword: _ _ #f) ...)) ..1))))
@ -378,7 +379,7 @@
(car doms*)) (car doms*))
(car rests*) (car rests*)
(car rngs*))) (car rngs*)))
=> (lambda (substitution) (do-ret (subst-all substitution (car rngs*))))] => finish]
;; actual work, when we have a * function and ... final arg ;; actual work, when we have a * function and ... final arg
[(and (car rests*) [(and (car rests*)
tail-bound tail-bound
@ -390,8 +391,7 @@
(car doms*)) (car doms*))
(car rests*) (car rests*)
(car rngs*))) (car rngs*)))
=> (lambda (substitution) => finish]
(do-ret (subst-all substitution (car rngs*))))]
;; ... function, ... arg, same bound on ... ;; ... function, ... arg, same bound on ...
[(and (car drests*) [(and (car drests*)
tail-bound tail-bound
@ -402,8 +402,7 @@
(cons (make-ListDots tail-ty tail-bound) arg-tys) (cons (make-ListDots tail-ty tail-bound) arg-tys)
(cons (make-ListDots (car (car drests*)) (cdr (car drests*))) (car doms*)) (cons (make-ListDots (car (car drests*)) (cdr (car drests*))) (car doms*))
(car rngs*))) (car rngs*)))
=> (lambda (substitution) => finish]
(do-ret (subst-all substitution (car rngs*))))]
;; ... function, ... arg, different bound on ... ;; ... function, ... arg, different bound on ...
[(and (car drests*) [(and (car drests*)
tail-bound tail-bound
@ -417,7 +416,7 @@
(cons (make-ListDots tail-ty tail-bound) arg-tys) (cons (make-ListDots tail-ty tail-bound) arg-tys)
(cons (make-ListDots (car (car drests*)) (cdr (car drests*))) (car doms*)) (cons (make-ListDots (car (car drests*)) (cdr (car drests*))) (car doms*))
(car rngs*))))) (car rngs*)))))
=> (lambda (substitution) (do-ret (subst-all substitution (car rngs*))))] => finish]
;; ... function, (List A B C etc) arg ;; ... function, (List A B C etc) arg
[(and (car drests*) [(and (car drests*)
(not tail-bound) (not tail-bound)
@ -427,8 +426,7 @@
(untuple tail-ty) (untuple tail-ty)
(infer/dots fixed-vars dotted-var (append arg-tys (untuple tail-ty)) (car doms*) (infer/dots fixed-vars dotted-var (append arg-tys (untuple tail-ty)) (car doms*)
(car (car drests*)) (car rngs*) (fv (car rngs*)))) (car (car drests*)) (car rngs*) (fv (car rngs*))))
=> (lambda (substitution) => finish]
(do-ret (subst-all substitution (car rngs*))))]
;; if nothing matches, around the loop again ;; if nothing matches, around the loop again
[else (loop (cdr doms*) (cdr rngs*) (cdr rests*) (cdr drests*))])))] [else (loop (cdr doms*) (cdr rngs*) (cdr rests*) (cdr drests*))])))]
[(tc-result1: (PolyDots: vars (Function: '()))) [(tc-result1: (PolyDots: vars (Function: '())))

View File

@ -11,6 +11,7 @@
syntax/struct syntax/struct
mzlib/trace mzlib/trace
unstable/debug unstable/debug
racket/function
scheme/match scheme/match
(for-syntax scheme/base)) (for-syntax scheme/base))
@ -197,9 +198,9 @@
;; then register them ;; then register them
(mk/register-sty nm flds parent-name parent-field-types types (mk/register-sty nm flds parent-name parent-field-types types
;; wrap everything in the approriate forall ;; wrap everything in the approriate forall
#:wrapper (lambda (t) (make-Poly tvars t)) #:wrapper (λ (t) (make-Poly tvars t))
#:type-wrapper (lambda (t) (make-App t new-tvars #f)) #:type-wrapper (λ (t) (make-App t new-tvars #f))
#:pred-wrapper (lambda (t) (subst-all (for/list ([t tvars]) (t-subst t Univ)) t)) #:pred-wrapper (λ (t) (subst-all (make-simple-substitution tvars (map (const Univ) tvars)) t))
#:poly? tvars)) #:poly? tvars))

View File

@ -9,15 +9,23 @@
scheme/contract) scheme/contract)
(provide subst-all substitute substitute-dots substitute-dotted subst (provide subst-all substitute substitute-dots substitute-dotted subst
(struct-out t-subst) (struct-out i-subst) (struct-out i-subst/starred) (struct-out i-subst/dotted)) (struct-out t-subst) (struct-out i-subst) (struct-out i-subst/starred) (struct-out i-subst/dotted)
substitution/c make-simple-substitution)
(define (subst v t e) (substitute t v e)) (define (subst v t e) (substitute t v e))
(d-s/c substitution ([name symbol?])) (d/c (make-simple-substitution vs ts)
(d-s/c (t-subst substitution) ([type Type/c])) (([vs (listof symbol?)] [ts (listof Type/c)]) () #:pre-cond (= (length vs) (length ts)) . ->d . [_ substitution/c])
(d-s/c (i-subst substitution) ([types (listof Type/c)])) (for/hash ([v (in-list vs)] [t (in-list ts)])
(d-s/c (i-subst/starred substitution) ([types (listof Type/c)] [starred Type/c])) (values v (t-subst t))))
(d-s/c (i-subst/dotted substitution) ([types (listof Type/c)] [dty Type/c] [dbound symbol?]))
(d-s/c subst-rhs ())
(d-s/c (t-subst subst-rhs) ([type Type/c]))
(d-s/c (i-subst subst-rhs) ([types (listof Type/c)]))
(d-s/c (i-subst/starred subst-rhs) ([types (listof Type/c)] [starred Type/c]))
(d-s/c (i-subst/dotted subst-rhs) ([types (listof Type/c)] [dty Type/c] [dbound symbol?]))
(define substitution/c (hash/c symbol? subst-rhs? #:immutable #t))
;; substitute : Type Name Type -> Type ;; substitute : Type Name Type -> Type
(d/c (substitute image name target #:Un [Un (get-union-maker)]) (d/c (substitute image name target #:Un [Un (get-union-maker)])
@ -130,16 +138,16 @@
;; substitution = Listof[U List[Name,Type] List[Name,Listof[Type]]] ;; substitution = Listof[U List[Name,Type] List[Name,Listof[Type]]]
;; subst-all : substitution Type -> Type ;; subst-all : substitution Type -> Type
(d/c (subst-all s t) (d/c (subst-all s t)
((listof substitution?) Type/c . -> . Type/c) (substitution/c Type? . -> . Type?)
(for/fold ([t t]) ([e s]) (for/fold ([t t]) ([(v r) s])
(match e (match r
[(t-subst v img) [(t-subst img)
(substitute img v t)] (substitute img v t)]
[(i-subst v imgs) [(i-subst imgs)
(substitute-dots imgs #f v t)] (substitute-dots imgs #f v t)]
[(i-subst/starred v imgs rest) [(i-subst/starred imgs rest)
(substitute-dots imgs rest v t)] (substitute-dots imgs rest v t)]
[(i-subst/dotted v imgs dty dbound) [(i-subst/dotted imgs dty dbound)
(int-err "i-subst/dotted nyi") (int-err "i-subst/dotted nyi")
#; #;
(substitute-dotted imgs rest v t)]))) (substitute-dotted imgs rest v t)])))

View File

@ -305,7 +305,7 @@
(=> unmatch) (=> unmatch)
(unless (= (length ns) (length ms)) (unless (= (length ns) (length ms))
(unmatch)) (unmatch))
(subtype* A0 b1 (subst-all (map t-subst ms (map make-F ns)) b2))] (subtype* A0 b1 (subst-all (make-simple-substitution ms (map make-F ns)) b2))]
[((Refinement: par _ _) t) [((Refinement: par _ _) t)
(subtype* A0 par t)] (subtype* A0 par t)]
;; use unification to see if we can use the polytype here ;; use unification to see if we can use the polytype here

View File

@ -40,13 +40,13 @@
[(Poly: ns body) [(Poly: ns body)
(unless (= (length types) (length ns)) (unless (= (length types) (length ns))
(int-err "instantiate-poly: wrong number of types: expected ~a, got ~a" (length ns) (length types))) (int-err "instantiate-poly: wrong number of types: expected ~a, got ~a" (length ns) (length types)))
(subst-all (map t-subst ns types) body)] (subst-all (make-simple-substitution ns types) body)]
[(PolyDots: (list fixed ... dotted) body) [(PolyDots: (list fixed ... dotted) body)
(unless (>= (length types) (length fixed)) (unless (>= (length types) (length fixed))
(int-err "instantiate-poly: wrong number of types: expected at least ~a, got ~a" (length fixed) (length types))) (int-err "instantiate-poly: wrong number of types: expected at least ~a, got ~a" (length fixed) (length types)))
(let* ([fixed-tys (take types (length fixed))] (let* ([fixed-tys (take types (length fixed))]
[rest-tys (drop types (length fixed))] [rest-tys (drop types (length fixed))]
[body* (subst-all (map t-subst fixed fixed-tys) body)]) [body* (subst-all (make-simple-substitution fixed fixed-tys) body)])
(substitute-dots rest-tys #f dotted body*))] (substitute-dots rest-tys #f dotted body*))]
[_ (int-err "instantiate-poly: requires Poly type, got ~a" t)])) [_ (int-err "instantiate-poly: requires Poly type, got ~a" t)]))
@ -56,7 +56,7 @@
(unless (= (length fixed) (length types)) (unless (= (length fixed) (length types))
(int-err "instantiate-poly-dotted: wrong number of types: expected ~a, got ~a, types were ~a" (int-err "instantiate-poly-dotted: wrong number of types: expected ~a, got ~a, types were ~a"
(length fixed) (length types) types)) (length fixed) (length types) types))
(let ([body* (subst-all (map t-subst fixed types) body)]) (let ([body* (subst-all (make-simple-substitution fixed types) body)])
(substitute-dotted image var dotted body*))] (substitute-dotted image var dotted body*))]
[_ (int-err "instantiate-poly-dotted: requires PolyDots type, got ~a" t)])) [_ (int-err "instantiate-poly-dotted: requires PolyDots type, got ~a" t)]))