git.fiddlerwoaroof.com
Raw Blame History
;;; 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))))