git.fiddlerwoaroof.com
type/dictionary.scm
4e987026
 
 ;;; 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))))