summaryrefslogtreecommitdiff
path: root/type/dictionary.scm
blob: 0a0260e5364d44608b697aed95e6f28e8aa300fd (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
;;; type/dictionary.scm

;;; This function supports dictionary conversion.  It creates lambda
;;; variables to bind to the dictionary args needed by the context.
;;; The actual conversion to lambda is done in the cfn.  Each tyvar in
;;; the context has an associated mapping from class to dictionary
;;; variable.  This mapping depends on the decl containing the placeholder
;;; since different recursive decls share common tyvars.  The mapping is
;;; two levels: decl -> class -> var.

;;; Due to language restrictions this valdef must be a simple variable
;;; definition.

(define (dictionary-conversion/definition valdef tyvars)
  (let* ((var (decl-var valdef))
	 (type (var-type var))
	 (context (gtype-context type))
	 (dict-param-vars '()))
    (dolist (c context)
      (let ((tyvar (car tyvars))
	    (dparams '()))
       (when (not (null? c))
	(dolist (class c)
          (let ((var (create-temp-var
		      (string-append "d_"
				     (symbol->string (def-name class))))))
	    (setf (var-force-strict? var) '#t)
	    (push (tuple class var) dparams)
	    (push var dict-param-vars)))
	(push (tuple valdef dparams) (ntyvar-dict-params tyvar)))
       (setf tyvars (cdr tyvars))))
    (setf (valdef-dictionary-args valdef) (nreverse dict-param-vars))))

;;; These routines deal with dict-var processing.

;;; This discharges the tyvars associated with dictionaries.  The dict-vars
;;; to be processed at the next level are returned.

(define (process-placeholders placeholders deferred decls)
  (if (null? placeholders)
      deferred
      (let ((d1 (process-placeholder (car placeholders) deferred decls)))
	(process-placeholders (cdr placeholders) d1 decls))))

;;; This processes a placeholder.  The following cases arise:
;;;  a) the variable has already been processed (no placeholders remain) -
;;;     ignore it.  placeholders may contain duplicates so this is likely.
;;;  b) the type variable is from an outer type environment (in ng-list)
;;;     and should just be passed up to the next level (added to old-placeholders)
;;;  c) the type variable is associated with a dictionary parameter
;;;  d) the type variable is instantiated to a type constructor
;;;  e) the type variable is ambiguous (none of the above)

(define (process-placeholder p deferred decls)
  (let* ((tyvar (placeholder-tyvar p))
	 (type (prune tyvar)))
    (cond ((ntycon? type)
	   (process-instantiated-tyvar
	    (expand-ntype-synonym type) p deferred decls))
	  ((non-generic? type)
	   (cons p deferred))
	  ((not (null? (ntyvar-dict-params type)))
	   (if (dict-placeholder? p)
	       (placeholder->dict-param p (ntyvar-dict-params type) decls)
	       (placeholder->method p (ntyvar-dict-params type) decls))
	   deferred)
	  (else
	   ;; Since default types are monotypes, no new vars will
	   ;; be added to old-placeholders
	   (when (maybe-default-ambiguous-tyvar
		  type (placeholder-overloaded-var p)
		  (valdef-module (car (placeholder-enclosing-decls p))))
	      (process-placeholder p deferred decls))
	   deferred))))
	       
;;; The type variable is associated with a dictionary parameter.  The only
;;; complication here is that the class needed may not be directly available -
;;; it may need to be obtained from the super classes of the parameter
;;; dictionaries.

(define (placeholder->dict-param p param-vars decls)
  (let ((class (dict-placeholder-class p))
	(edecls (dict-placeholder-enclosing-decls p)))
    (setf (placeholder-exp p)
	  (dict-reference-code class (locate-params param-vars edecls decls)))))

(define (dict-reference-code class param-vars)
  (let ((var (assq class param-vars)))
    (if (not (eq? var '#f))
	(**var/def (tuple-2-2 var))
	(search-superclasses class param-vars))))

(define (locate-params param-vars enclosing-decls decls)
  (if (null? (cdr param-vars))
      (tuple-2-2 (car param-vars))
      (let ((decl (search-enclosing-decls enclosing-decls decls)))
	(tuple-2-2 (assq decl param-vars)))))

;;; This finds the first dictionary containing the needed class in its
;;; super classes and generates a selector to get the needed dictionary.

(define (search-superclasses class param-vars)
  (let ((pclass (tuple-2-1 (car param-vars))))
    (if (memq class (class-super* pclass))
	(**dsel/dict pclass class (**var/def (tuple-2-2 (car param-vars))))
	(search-superclasses class (cdr param-vars)))))

(define (placeholder->method p param-vars decls)
  (let* ((method (method-placeholder-method p))
	 (class (method-var-class method))
	 (edecls (placeholder-enclosing-decls p))
	 (params (locate-params param-vars edecls decls)))
    (setf (placeholder-exp p)
	  (method-reference-code method class params))))

(define (method-reference-code m c param-vars)
 (let ((pclass (tuple-2-1 (car param-vars))))
  (if (or (eq? c pclass)
	  (memq c (class-super* pclass)))
      (let* ((msel (assq m (class-selectors pclass)))
	     (mvar (tuple-2-2 msel)))
	(**app (**var/def mvar) (**var/def (tuple-2-2 (car param-vars)))))
      (method-reference-code m c (cdr param-vars)))))

;;; This is for tyvars instantiated to a tycon.  A reference to the
;;; appropriate dictionary is generated.  This reference must be recursively
;;; dictionary converted since dictionaries may need subdictionaries
;;; when referenced.

(define (process-instantiated-tyvar tycon p deferred decls)
  (let* ((alg (ntycon-tycon tycon))
	 (edecls (placeholder-enclosing-decls p))
	 (var (placeholder-overloaded-var p))
	 (class (if (dict-placeholder? p)
		    (dict-placeholder-class p)
		    (method-var-class (method-placeholder-method p))))
	 (instance (lookup-instance alg class)))
    (if (dict-placeholder? p)
	(mlet (((code def1)
		(generate-dict-ref instance tycon deferred decls edecls var)))
	   (setf (placeholder-exp p) code)
	   (setf deferred def1))
	(let ((method (method-placeholder-method p)))
	  (if (every (function null?) (instance-gcontext instance))
	      (let ((mvar (tuple-2-2
			   (assq method (instance-methods instance)))))
		(setf (placeholder-exp p) (**var/def mvar)))
	      (mlet (((code def1)
		      (generate-dict-ref
		         instance tycon deferred decls edecls var))
		     (sel (tuple-2-2 (assq method (class-selectors class)))))
		(setf (method-placeholder-exp p) (**app (**var/def sel) code))
		(setf deferred def1)))))
    deferred))

;;; This generates a reference to a specific dictionary and binds
;;; needed subdictionaries.  Since subdictionaries may be part of the outer
;;; type environment new placeholders may be generated for later resolution.

(define (generate-dict-ref instance type deferred decls edecls var)
  (let* ((ctxt (instance-gcontext instance))
	 (dict (dict-ref-code instance)))
    (do-contexts (class ctxt) (ty (ntycon-args type))
      (let ((ntype (prune ty)))
	(cond
	 ((ntycon? ntype)
	  (mlet ((ntype (expand-ntype-synonym ntype))
		 (alg (ntycon-tycon ntype))
		 (instance (lookup-instance alg class))
		 ((code dv1)
		  (generate-dict-ref
		    instance ntype deferred decls edecls var)))
	      (setf dict (**app dict code))
	      (setf deferred dv1)))
	 ((non-generic? ntype)
	  (let ((p (**dict-placeholder
		    class ntype edecls var)))
	    (setf dict (**app dict p))
	    (push p deferred)))
	 ((null? (ntyvar-dict-params ntype))
	  (let ((ref-code (**dict-placeholder
			   class ntype edecls var)))
	     (when (maybe-default-ambiguous-tyvar
		    ntype var (valdef-module (car edecls)))
		(process-placeholder ref-code '() decls))
	     (setf dict (**app dict ref-code))))
	 (else
	  (let ((p (locate-params (ntyvar-dict-params ntype) edecls decls)))
	    (setf dict (**app dict (dict-reference-code class p))))))))
    (values dict deferred)))

;;; The following routines deal with recursive placeholders.  The basic
;;; strategy is to pass the entire context as a parameter with each
;;; recursive call (this could be optimized later to make use of an
;;; internal entry point).  The basic complication is that the context
;;; of each function in a letrec may be arranged differently.

;;; This generates a call inside decl 'from' to the var 'to'.  Vmap is an
;;; alist from vars to a list of vars corresponding to the gtyvars of
;;; the decl signature.

(define (recursive-call-code from to vmap)
  (let ((exp (**var/def to))
	(tyvars (tuple-2-2 (assq to vmap)))
	(contexts (gtype-context (var-type to))))
    (do-contexts (class contexts) (tyvar tyvars)
       (setf exp (**app exp (locate-param-var tyvar class from))))
    exp))

(define (locate-param-var tyvar class decl)
  (let ((vmap (tuple-2-2 (assq decl (ntyvar-dict-params tyvar)))))
    (**var/def (tuple-2-2 (assq class vmap)))))

;;; This is used to get the code for a specific dictionary reference.

(define (dict-ref-code instance)
  (**var/def (instance-dictionary instance)))

;;; This is used to locate the correct enclosing decl.

(define (search-enclosing-decls decl-list decls)
  (cond ((null? decl-list)
	 (error "Lost decl in search-enclosing-decls!"))
	((memq (car decl-list) decls)
	 (car decl-list))
	(else
	 (search-enclosing-decls (cdr decl-list) decls))))