Skip to content

Commit c208535

Browse files
committed
WIP F-bounded Polymorphism
1 parent 668a0d5 commit c208535

File tree

4 files changed

+65
-26
lines changed

4 files changed

+65
-26
lines changed

typed-racket-lib/typed-racket/infer/infer-unit.rkt

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
(define (empty-set) '())
4040

4141
(define current-seen (make-parameter (empty-set)))
42+
(define infered-tvar-map (make-parameter (hash)))
4243

4344
;; Type Type -> Pair<Seq, Seq>
4445
;; construct a pair for the set of seen type pairs
@@ -476,7 +477,7 @@
476477
;; produces a cset which determines a substitution that makes S a subtype of T
477478
;; implements the V |-_X S <: T => C judgment from Pierce+Turner, extended with
478479
;; the index variables from the TOPLAS paper
479-
(define/cond-contract (cgen context S T [obj #f] [bound #f])
480+
(define/cond-contract (cgen context S T [obj #f])
480481
(->* (context? (or/c Values/c ValuesDots? AnyValues?)
481482
(or/c Values/c ValuesDots? AnyValues?))
482483
((or/c #f OptObject?))
@@ -485,7 +486,7 @@
485486
(define/cond-contract (cg S T [obj #f])
486487
(->* (Type? Type?) ((or/c #f OptObject?))
487488
(or/c #f cset?))
488-
(cgen context S T obj bound))
489+
(cgen context S T obj))
489490
(define/cond-contract (cg/inv S T)
490491
(Type? Type? . -> . (or/c #f cset?))
491492
(cgen/inv context S T))
@@ -496,7 +497,15 @@
496497
(insert empty x S T))
497498

498499
(define (constrain tvar-a tvar-b #:above above)
499-
(match-define (F: var maybe-type-bound) tvar-a)
500+
(define (maybe-type-app t)
501+
(match t
502+
[(App: t1 (list (F: var))) #:when (hash-has-key? (infered-tvar-map) var)
503+
(define v (hash-ref (infered-tvar-map) var))
504+
(-App t1 (list v))]
505+
[_ t]))
506+
507+
(match-define (F: var (app maybe-type-app maybe-type-bound)) tvar-a)
508+
500509
(define-values (default sub sing) (if above
501510
(values Univ
502511
(thunk (subtype tvar-b maybe-type-bound obj))
@@ -506,7 +515,9 @@
506515
(curryr singleton var (var-demote tvar-b (context-bounds context))))))
507516
(cond
508517
[(not maybe-type-bound) (sing default)]
509-
[(sub) (sing maybe-type-bound)]
518+
[(sub)
519+
(infered-tvar-map (hash-set (infered-tvar-map) var maybe-type-bound))
520+
(sing maybe-type-bound)]
510521
[else #f]))
511522

512523
;; FIXME -- figure out how to use parameters less here
@@ -983,6 +994,7 @@
983994
(build-subst md))
984995
(build-subst (stream-first (cset-maps C)))))
985996

997+
986998
;; context : the context of what to infer/not infer
987999
;; S : a list of types to be the subtypes of T
9881000
;; T : a list of types
@@ -1000,9 +1012,9 @@
10001012
(for/list/fail ([s (in-list S)]
10011013
[t (in-list T)]
10021014
[obj (in-list/rest objs #f)])
1003-
;; We meet early to prune the csets to a reasonable size.
1004-
;; This weakens the inference a bit, but sometimes avoids
1005-
;; constraint explosion.
1015+
;; We meet early to prune the csets to a reasonable size.
1016+
;; This weakens the inference a bit, but sometimes avoids
1017+
;; constraint explosion.
10061018
(% cset-meet (cgen context s t obj) expected-cset)))))
10071019

10081020

@@ -1048,16 +1060,17 @@
10481060
;; like infer, but T-var is the vararg type:
10491061
(define (infer/vararg X Y S T T-var R [expected #f]
10501062
#:objs [objs '()])
1051-
(and ((length S) . >= . (length T))
1052-
(let* ([fewer-ts (- (length S) (length T))]
1053-
[new-T (match T-var
1054-
[(? Type? var-t) (list-extend S T var-t)]
1055-
[(Rest: rst-ts)
1056-
#:when (zero? (remainder fewer-ts (length rst-ts)))
1057-
(append T (repeat-list rst-ts
1058-
(quotient fewer-ts (length rst-ts))))]
1059-
[_ T])])
1060-
(infer X Y S new-T R expected #:objs objs))))
1063+
(parameterize ([infered-tvar-map (hash)])
1064+
(and ((length S) . >= . (length T))
1065+
(let* ([fewer-ts (- (length S) (length T))]
1066+
[new-T (match T-var
1067+
[(? Type? var-t) (list-extend S T var-t)]
1068+
[(Rest: rst-ts)
1069+
#:when (zero? (remainder fewer-ts (length rst-ts)))
1070+
(append T (repeat-list rst-ts
1071+
(quotient fewer-ts (length rst-ts))))]
1072+
[_ T])])
1073+
(infer X Y S new-T R expected #:objs objs)))))
10611074

10621075
;; like infer, but dotted-var is the bound on the ...
10631076
;; and T-dotted is the repeated type

typed-racket-lib/typed-racket/private/parse-type.rkt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,9 @@
195195

196196
(define-syntax-class maybe-bounded
197197
#:datum-literals (<:)
198-
(pattern (name:id <: bound:id)))
198+
#:attributes (name bound)
199+
(pattern (name:id <: bound:expr))
200+
(pattern name:id #:attr bound #f))
199201

200202
;; Syntax -> Type
201203
;; Parse a Forall type
@@ -224,9 +226,12 @@
224226
(when maybe-dup
225227
(parse-error "duplicate type variable"
226228
"variable" (syntax-e maybe-dup)))
227-
(define bounds (for/hash ([i (stx-map syntax-e (attribute vars.name))]
228-
[j (attribute vars.bound)])
229-
(values i (parse-type j))))
229+
(define bounds (for/fold ([acc (hash)])
230+
([i (stx-map syntax-e (attribute vars.name))]
231+
[j (attribute vars.bound)]
232+
#:when j)
233+
(hash-set acc i
234+
(extend-tvars (hash-keys acc) (parse-type j)))))
230235
(let* ([vars (stx-map syntax-e (attribute vars.name))])
231236
(extend-tvars vars
232237
(make-Poly vars (parse-type #'t.type) #:bounds bounds)))]

typed-racket-lib/typed-racket/rep/type-rep.rkt

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
syntax/id-set
2525
racket/contract
2626
racket/lazy-require
27+
racket/syntax
2728
racket/unsafe/undefined
2829
(for-syntax racket/base
2930
racket/syntax
@@ -110,6 +111,7 @@
110111
(App? x)))
111112

112113
(lazy-require
114+
("../types/substitute.rkt" (subst))
113115
("../types/overlap.rkt" (overlap?))
114116
("../types/prop-ops.rkt" (-and))
115117
("../types/resolve.rkt" (resolve-app))
@@ -1660,28 +1662,37 @@
16601662
;;
16611663
;; list<symbol> type #:original-names list<symbol> -> type
16621664
;;
1665+
16631666
(define (Poly* names body #:bounds [bounds '#hash()] #:original-names [orig names])
16641667
(if (null? names) body
16651668
(let* ([len (length names)]
1666-
[new-bounds (let ([max-idx (sub1 len)])
1667-
(for/hash ([(n v) bounds])
1668-
(values (- max-idx (index-of names n)) v)))]
1669+
[new-bounds (for/hash ([(n v) bounds])
1670+
(values (index-of names n) v))]
16691671
[v (make-Poly len new-bounds (abstract-type body names))])
16701672
(hash-set! type-var-name-table v orig)
16711673
v)))
16721674

1675+
(define (unsubst ty orig-names names)
1676+
(for/fold ([acc ty])
1677+
([o orig-names]
1678+
[n names])
1679+
(subst o (make-F n #f) acc)
1680+
#;
1681+
(subst o (make-Name (format-id #f "~a" n) 0 #f) acc)))
1682+
16731683
;; Poly 'smart' destructor
16741684
(define (Poly-body* names t)
1685+
(define orig-names (hash-ref type-var-name-table t))
16751686
(match t
16761687
[(Poly: n bounds body)
16771688
(define new-bounds (for/hash ([(idx v) bounds])
1678-
(values (list-ref names idx) v)))
1689+
(values (list-ref names idx) (unsubst v orig-names names))))
16791690
(unless (= (length names) n)
16801691
(int-err "Wrong number of names: expected ~a got ~a" n (length names)))
16811692
(instantiate-type body
16821693
(map (lambda (n)
16831694
(make-F n (hash-ref new-bounds n #f)))
1684-
names))]))
1695+
names))]))
16851696

16861697
;; PolyDots 'smart' constructor
16871698
(define (PolyDots* names body)

typed-racket-test/succeed/bounded-poly.rkt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,13 @@
77

88

99
(a-func 10) ;; pass
10+
11+
12+
(struct (A) foo ([a : A]) #:type-name Foo)
13+
14+
(: c-func (All ([X <: Integer] [Y <: (Foo X)])
15+
(-> X Y String)))
16+
(define (c-func a b)
17+
(number->string a))
18+
19+
(c-func 10 (foo 10))

0 commit comments

Comments
 (0)