;;; -*- mode:lisp;package:user;base:10.;fonts:(cptfontb) -*- 
;;; $Header: /ct/interp/resolve.l,v 1.39 84/12/07 16:32:53 penny Exp $

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                            resolve.l                             ;;;
;;; Paul Robertson                                  October 18, 1983 ;;;
;;;                                                                  ;;;
;;;       The C*T Ada Interpreters Static Semantic support           ;;;
;;;                                                                  ;;;
;;; This file is part of a proprietary software project.  Source     ;;;
;;; code and documentation describing implementation details are     ;;;
;;; available on a confidential, non-disclosure basis only.  These   ;;;
;;; materials, including this file in particular, are trade secrets  ;;;
;;; of Computer * Thought Corporation.                               ;;;
;;;                                                                  ;;;
;;; (c) Copyright 1982 and 1983,  Computer * Thought Corporation.    ;;;
;;;     All Rights Reserved.                                         ;;;
;;;                                                                  ;;;
;;; Reference materials:                                             ;;;
;;;   Miller, 1982.  The C*T Ada Tutor: Guide to the Implementation. ;;;
;;;   Charniak et al., 198?.  Artificial Intelligence Programming.   ;;;
;;;                                                                  ;;;
;;; The following code assumes familiarity with the above.           ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Ensure presence of needed files. 


(eval-when (compile load eval) (ct_load 'aip))	      ;AIP macros pkg. 

(eval-when (compile load eval) (ct_load 'compat))     ;Franz/LM compat pkg. 

(eval-when (compile load eval) (ct_load 'charmac))

(eval-when (compile load eval) (ct_load 'time))       ;Timing functions. 

(eval-when (compile load eval) (ct_load 'diana))      ; Diana tools.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Compiler Declarations and Global Variables -- 

#+franz (declare (macros t))
(declare (ct_includef 'intrpdcl))		; get the specials
(eval-when (compile load eval) (ct_load 'ferec))	; get the macros etc.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Externally Call-able Functions/Macros -- 

;;; Static semantic code schemas are structured as follows.
;;; Body contains lisp code that returns a piece of diana tree or nil.
;;; The main way of building a diana tree is with the sc_diana functon.
;;; Simple node will consist only of these nodes. sc_diana looks like this...
;;; (sc_diana dn_foo slotname code slotname code slotname code .. .. .. ..)
;;; The above example creates a diana node with the names slots, and calls the
;;; appropriate code to fill the slots. One reason why this function should be
;;; used is that it hides the internal representation of a diana node making
;;; future modifications easy (which would be necessary for say a production
;;; compiler.
;;; The abstract syntax is available for inclusion in  the diana tree or
;;; other in a free variable called *abstract_syntax*. This variable may be
;;; altered by the code for effeciency reasons without intefering with the
;;; parsing process. Syntax nodes that do not have ssemantics code will
;;; produce abstract syntax subtree's. To return a null node have a ssemantic
;;; property that returns nil.

;;; if the function reference is not ambiguous, wire it in, otherwise
;;; put it on the  *awaiting_disambiguation* list till later.

;;; ++ this function should check that the indices legal for this choice
;;;    and return non nil if OK.

       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun returns_array_with_compatible_indicesp (choice)
       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  (and (eq(diana_nodetype_get choice) 'dn_function_id) t));++unfinished

       ;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun result_type_after_indexing (choice)
       ;;;;;;;;;;;;;;;;;;;;;;;;;;

  (let* ((spec (diana_get choice 'sm_spec))
	 (rtntyp (and spec (extract_basetype (diana_get spec 'as_name_void))))
	 (arrtyp
	   (and rtntyp
		(cond
		  ((diana_node_accepts_attributep rtntyp 'as_constrained)
		   (extract_basetype (diana_get rtntyp 'as_constrained)))
		  (t rtntyp)))))
    arrtyp))

       ;;;;;;;;;;;;;;;;;;;;;;;;;
(defun coerce_funcall_to_indexed (dn)
       ;;;;;;;;;;;;;;;;;;;;;;;;;

  (let ((indices (diana_get dn 'as_param_assoc_s)))
    (diana_nodetype_set dn 'dn_indexed)
    (diana_put dn nil 'ct_parent_type)
    (diana_put dn nil 'ct_base_type)
    (diana_put dn indices 'as_exp_s)
    (diana_put dn
	       (sc_diana dn_function_call
			 as_name
			 (let ((choice (car (diana_get dn 'tp_vfuns))))
			   (sc_diana dn_used_name_id
				     lx_symrep (diana_get choice 'lx_symrep)
				     sm_defn choice)))
	       'as_name)))

(declare (special labels_alist labels_alist2))	  ;used in several places!

       ;;;;;;;;;;;
(defun subprog_bit (ch)
       ;;;;;;;;;;;
  (cond ((null ch) nil)
	((eq (diana_nodetype_get ch) 'dn_selected)
	 (diana_get ch 'as_designator_char))
	 (t ch)))

       ;;;;;;;;;;;;;;;;;;;;;;;
(defun filter_static_functions (dn choices)
       ;;;;;;;;;;;;;;;;;;;;;;;
  (cond ((= (length choices) 1) choices)
	
	((all_actuals_are_universal_static_expressions_p
	   (let ((aps (diana_get dn 'as_param_assoc_s)))
	     (and aps (diana_get aps 'as_list))))
	 (let ((wazzoo_funs
		 (mapcan #'(lambda (fn)
			     (cond
			       ((universal_function_p fn) (list fn))))
			 choices)))
	   (cond (wazzoo_funs  wazzoo_funs)
		 (t choices))))
	(t choices)))

       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun dissambiguate_function_reference (dn)
       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;(break in-dissambiguate-func-ref)
  (cond ((memq dn *awaiting_parameter_normalization*)
	 (normalize_params dn)))
  (let ((choices (filter_static_functions
		   dn
		   (filter_matching_functions dn (diana_get dn 'tp_vfuns)))))
					  ;(break look-at-choices)
    ;; choices is candidates filter based on subordinate types.
    (cond
      ((eq
       (*catch
	 'still_ambiguous
	 (cond ((= (length choices) 1);(break frob)
		;;compare type with expected type for this node.
		(let* ((labels_alist
			 (car
			   ;;pass the type of each parameter to the corresponding
			   ;;actual subtree if it has a 'nil' exp_type.
			   (consistant_type_profilep
			     (let ((apas (diana_get dn 'as_param_assoc_s)))
			       (and apas (diana_get apas 'as_list)))
			     (let ((sms (diana_get
					  (subprog_bit (car choices)) 'sm_spec)))
			       (and sms (diana_get sms 'as_param_s)))
			     t)))	  ;persuader!
		       (labels_alist2
			 (and
			   (let ((apas (diana_get dn 'as_param_assoc_s)))
			       (and apas (diana_get apas 'as_list)))
			   (returns_array_with_compatible_indicesp
			     (subprog_bit (car choices)))
			   (car
			     (consistant_type_profilep
			       nil
			       (let ((sms (diana_get
					    (subprog_bit (car choices)) 'sm_spec)))
				 (and sms (diana_get sms 'as_param_s)))
			       t))))
		       (expected_type
			 (cond ((eq (diana_nodetype_get dn) 'dn_function_call)
				(diana_get dn 'sm_exp_type)))))
		  ;(break frob2)
		  (cond ((or
			   (not (eq (diana_nodetype_get dn) 'dn_function_call))
			   (and
			     (or (not labels_alist) expected_type)
			     labels_alist2
			     (consistant_types_with_inheritance labels_alist2
			       expected_type	
			       (result_type_after_indexing
				 (subprog_bit (car choices))))
			     (coerce_funcall_to_indexed dn))
			   (and
			     (or (not labels_alist2) expected_type)
			     (consistant_types_with_inheritance labels_alist
			       expected_type	  ;this will be NIL if a procedure!
			       (substituted_derived_type
				 (diana_get
				   (diana_get
				     (subprog_bit (car choices)) 'sm_spec)
				   'as_name_void)
				 labels_alist)))
			   (and
			     expected_type
			     (derivable_subprogram
			       expected_type
			       (diana_get
				 (diana_get (subprog_bit (car choices)) 'sm_spec)
				 'as_name_void)))))
			((and labels_alist labels_alist2)
			 ;;there is still an ambiguity about funcall/arrindex.
			 (*throw 'still_ambiguous 'still_ambiguous))
			(t (semgripe 'type_mismatch_in_subprog
				     (let* ((spb (subprog_bit (car choices)))
					    (lxs (and spb
						      (find_selected_name spb))))
				       (implode
					 (cadr lxs))))))
		  ;;now proporgate the type if its a function..
		  (cond
		    ((eq (diana_nodetype_get dn) 'dn_function_call)
		     ;(break foo)
		     (cond ((and (universal_function_p (car choices))
				 (all_actuals_are_universal_static_expressions_p
				   (let ((aps (diana_get dn 'as_param_assoc_s)))
				     (and aps (diana_get aps 'as_list)))))
			    (let ((ret (substituted_derived_type
					 (extract_basetype
					   (diana_get
					     (diana_get
					       (subprog_bit (car choices))
					       'sm_spec)
					     'as_name_void))
					 labels_alist)))
			    ;(break look-at-ret)
				  (cond ((eq ret (extract_basetype
						   *universal_float*))
					 (diana_put dn
						    *universal_real*
						    'sm_exp_type))
					(t
					 (diana_put dn
						    ret
						    'sm_exp_type)))))
			   (t
			    (diana_put dn
				(substituted_derived_type
				  (extract_basetype
				    (diana_get
				      (diana_get
					(subprog_bit (car choices)) 'sm_spec)
				      'as_name_void))
				  labels_alist)
				'sm_exp_type))))))
		;;and wire it in.
		(diana_put dn
			   (sc_diana dn_used_name_id
				     lx_symrep
				     (let* ((spb (subprog_bit (car choices)))
					    (lxs (and spb
						      (find_selected_name spb))))
				       lxs)
				     sm_defn (car choices))
			   'as_name)
		;;check that its parameters have been normalized.
		(cond ((null (diana_get dn 'sm_normalized_param_s))
		       (%= *awaiting_parameter_normalization* (delq dn *_*))
		       (normalize_params dn)))
		;;now see if this disambiguation can be proportated down to any
		;;of the subortinate subtrees.
		(disambiguate_subordinate_subtrees dn)
		;; If this function call was really an enumeration literal
		;; then we need to clobber the function call with the
		;; dn_used_name_id.
		(cond ((memq (diana_nodetype_get (car choices))
			     '(dn_enum_id dn_def_char))
		       (let ((id (sc_diana dn_used_name_id
					   lx_symrep (diana_get
						       (car choices)
						       'lx_symrep)
					   sm_defn (car choices))))
;		    (break about-to-lose)
;		    (rplaca dn (car id))
;		    (rplacd dn (cdr id))
			 (diana_nodetype_set dn (diana_nodetype_get id))
			 (diana_mapc
			   #'(lambda(attr val)
			       (diana_put dn val attr))
			   id)
;		    (break have-a-quick-peek-at-dn)
			 )))
		;; This node is no longer waiting to be disambiguated.
		;;so if it was on the waiting list, remove it.
		
		(diana_put dn nil 'tp_vfuns)	  ;this is it discard temporary.
		(%=   *awaiting_disambiguation*  (delq dn *_*)))
	       ((null choices)		  ;no matching function found.
		(let* ((chs (diana_get dn 'tp_vfuns))
		       (nm  (and chs (find_selected_name (car chs)))))
		  (cond
		    ((null chs)
		     (%=   *awaiting_disambiguation*  (delq dn *_*))
		     (semgripe 'undecl_subprog))
		    ;; operator is undefined but in ada equality and inequality
		    ;; is always defined, so put one in.
		    ((equal (cadr nm) '(#/=))
		     ;;now proporgate the type if its a function..
		     (cond
		       ((eq (diana_nodetype_get dn) 'dn_function_call)
			(diana_put dn
				   (diana_get
				     (diana_get
				       (ada_declared
					 (ada_ident **any_equal**)
					 nil)
				       'sm_spec)
				     'as_name_void)
				   'sm_exp_type)))
		     (diana_put dn
				(sc_diana dn_used_name_id
					  lx_symrep (ada_ident =)
					  sm_defn (ada_declared
						    (ada_ident **any_equal**)
						    nil))
				'as_name)
		     (%=   *awaiting_disambiguation*  (delq dn *_*)))
		    ;; operator is undefined but in ada equality and inequality
		    ;; is always defined, so put one in.
		    ((equal (cadr nm) '(#// #/=))
		     (diana_put dn
				(sc_diana dn_used_name_id
					  lx_symrep (ada_ident /=)
					  sm_defn (ada_declared
						    (ada_ident **any_equal**)
						    nil))
				'as_name)
		     (%=   *awaiting_disambiguation*  (delq dn *_*)))
		    (t			  ;(break in-t-state)
		     (%=   *awaiting_disambiguation*  (delq dn *_*))
		     (semgripe 'undecl_subprog
			       (let* ((tpvfuns (first (diana_get dn 'tp_vfuns)))
				      (lxsr (and
					      tpvfuns
					      (find_selected_name tpvfuns))))
				 (implode
				   (cadr
				     lxsr)))))))) 
	       (t
		;; remember current state of disambiguation.
		(diana_put dn choices 'tp_vfuns)
		;; and wait for another shot at it.
		(cond
		  ((memq dn  *awaiting_disambiguation*))
		  (t (ct_push dn *awaiting_disambiguation*))))))
       'still_ambiguous)
      ;; remember current state of disambiguation.
      (diana_put dn choices 'tp_vfuns)
      (diana_put dn nil 'ct_base_type)
      (diana_put dn nil 'ct_parent_type)
      ;; and wait for another shot at it.
      (cond
       ((memq dn  *awaiting_disambiguation*))
       (t (ct_push dn *awaiting_disambiguation*))))))
dn)

       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun check_pending_disambiguations ()
       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; First of all give the waiting list a chance to be disambiguated.
  (%= *awaiting_disambiguation*
      (mapcan
	#'(lambda(dp)
	    ;;try to disambiguate this one.
	    (dissambiguate_function_reference dp)
	    ;;if it succeeded, remove it from the pending list.
	    (cond ((null (diana_get dp 'tp_vfuns))
		   nil)
		  (t
		   (list dp))))
	*_*))
  ;; Any remaining in the list are ambiguous.. Say so.
  (mapc
    #'(lambda(loser)
	(semgripe 'ambig_func_ref))
    *awaiting_disambiguation*)
  ;;now clean out the list for next time.
  (setq *awaiting_disambiguation* nil)
)
       ;;;;;;;;;;;;;;;;
(defun any_params_fixed(fn)
       ;;;;;;;;;;;;;;;;
  (let ((pars (diana_get
		(diana_get fn 'sm_spec)
		'as_param_s)))
    (do ((par pars (cdr par))
	 (btu (extract_basetype *universal_fixed*)))
	((null par) nil)
      (cond ((eq btu
		 (extract_basetype
		   (car (diana_get (car par) 'as_id_s))))
	     (return t))))))

;;see if this is a universal operator- ie in the wazzoo
;;and return **any_float**
       ;;;;;;;;;;;;;;;;;;;;
(defun universal_function_p (fn)
       ;;;;;;;;;;;;;;;;;;;;

  (let* ((path (source_region%path
		(and (diana_node_accepts_attributep fn 'sm_body)
		     (diana_get fn 'sm_body)
		     (diana_get
		       (diana_get fn 'sm_body)
		       'lx_srcpos))))
	(smspec (and (diana_node_accepts_attributep fn 'sm_spec)
		       (diana_get
			 fn
			 'sm_spec)))
	(rettyp (and smspec
		     (diana_node_accepts_attributep smspec 'as_name_void)
		     (diana_get
		       smspec
		       'as_name_void))))
    (cond ((and (equal path '"wazzoo")
		(eq (extract_basetype rettyp)
		    (extract_basetype *ct_ada_true* )))
	   (cond ((not (any_params_fixed fn))
		  t)))
	  ((and (equal path '"wazzoo")
		(neq rettyp *universal_fixed*))
	   t))
	  ))

;;checks that each of the actuals is a universal expression
       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun all_actuals_are_universal_static_expressions_p (al)
       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (not (memq '*diana_node_not_static_expression*
	(mapcar
	  #'(lambda (act)
	    (car (errset (fe_static_eval act) nil)))
	  al))))

;;; discard variants that could never suceed by virtue of the types of the
;;; actuals - if known.
 
       ;;;;;;;;;;;;;;;;;;;;;;;;;
(defun filter_matching_functions (dn choices)
       ;;;;;;;;;;;;;;;;;;;;;;;;;
	(let ((actuals (let ((aps (diana_get dn 'as_param_assoc_s)))
			 (and aps (diana_get aps 'as_list)))))
	  (mapcan
	    #'(lambda(choice)		  ;do actuals match formals?
		(cond
		  ((eq (diana_nodetype_get choice) 'dn_selected)
		   (mapcar #'(lambda (fn)
				 (sc_diana dn_selected
					 as_name (diana_get choice 'as_name)
					 as_designator_char fn)
			       )
			   (filter_matching_functions
				dn
				(let ((asdes
					(diana_get choice 'as_designator_char)))
				  (cond ((consp asdes) asdes)
					((null asdes ) nil)
					(t (list asdes)))))))
		  (t
		   (let* ((spec
			    (and
			      (diana_node_accepts_attributep choice 'sm_spec)
			      (diana_get choice 'sm_spec)))
			  (formals 
			    (and spec
				 (diana_get spec 'as_param_s))))
;	    (break in-filter)
		     (let ((labels_alist
			     (consistant_type_profilep actuals formals))
			   (labels_alist2
			     (consistant_type_profilep nil formals)))
;	      (break frob)
		       (cond
			 ((and actuals (not formals)) nil)
			 ((and labels_alist
			       (or
				 (not
				   (eq (diana_nodetype_get dn) 'dn_function_call))
				 (consistant_types_with_inheritance
				   labels_alist
				   (diana_get dn 'sm_exp_type)
				   (substituted_derived_type
				     (diana_get spec 'as_name_void)
				     (car labels_alist)))
				 (derivable_subprogram
				   (diana_get dn 'sm_exp_type)
				   (diana_get spec 'as_name_void))))
			  (list choice))
			 ((and labels_alist2
			       (eq (diana_nodetype_get dn) 'dn_function_call)
			       (or
				 (consistant_types_with_inheritance
				   labels_alist2
				   (diana_get dn 'sm_exp_type)
				   (result_type_after_indexing choice))
				 (derivable_subprogram
				   (diana_get dn 'sm_exp_type)
				   (diana_get spec 'as_name_void))))
			  (list choice))
			 (t nil)))	  ;cant be this function.
		     )))
		)
	    choices))
	   )

       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun disambiguate_subordinate_subtrees  (dn)
       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (let ((actuals
	  (let ((apas (diana_get dn 'as_param_assoc_s)))
	    (and apas (diana_get apas 'as_list)))))
    (mapc
      #'(lambda(subordinate)
	  (cond ((memq subordinate *awaiting_disambiguation*)
		 (dissambiguate_function_reference subordinate))
		((memq subordinate *awaiting_aggregate_disambiguation*)
		 (dissambiguate_aggregate subordinate dn))));cul++
      actuals)))

       ;;;;;;;;;;;;;;;;;;;;;;;;
(defun consistant_type_profilep (actuals formals &optional persuader)
       ;;;;;;;;;;;;;;;;;;;;;;;;
    ;;step through actuals. If base type can be established, use it
    ;;if it can't skip to the next one. If a nonmatching basetype is found
    ;;return 'nil'. If all match or are unknown, return a list whose 'car'
    ;;is the labels_alist mapping of formals onto derived types, for use in
    ;;type propergation.
    ;;now, it just so happens that the actual might be a private type
    ;;and the actual aint. In this case, the private formal is coerced into
    ;;its 'hidden' basetype.
  (*catch '*unmatched_keyword*
    (progn
    (setq formals (extract_formal_id_s formals))
    (setq actuals
	  (sort_actuals_into_the_correct_order_if_possible actuals formals))
    (cond
      ((= (length actuals)(length formals))
       (do ((acts actuals (cdr acts))
	    (frms formals (cdr frms))
	    (labels_alist nil))		  ;a list of type maps for derived types.
	   ((null acts)
	    (list labels_alist))	  ;this one is consistant.
	 (let ((actual_basetype (extract_basetype (car acts)))
	       (formal_basetype
		 (substituted_derived_type
		   (extract_basetype (diana_get (caar frms) 'sm_obj_type))
						;;(cadar frms))
		   labels_alist)))
#|	   (cond ((and (not (private_type_p formal_basetype))
		       (private_type_p actual_basetype)
		       (diana_get actual_basetype 'sm_type_spec))
		  (setq actual_basetype
			(extract_basetype
			  (diana_get actual_basetype 'sm_type_spec)))))|#
	   (cond ((and persuader (not actual_basetype))
		  (diana_put (car acts) formal_basetype 'sm_exp_type)))
	   (cond 
	     ;;check possible constraint generated by literals.
	     ((ada_literal_or_aggregate_p (car acts))
	      (cond ((not (formal_consistant_with_literalp
			    formal_basetype
			    (car acts)))
		     (return nil))))
	     ((and actual_basetype
		   formal_basetype
		   (not
		     (derivable_subprogram actual_basetype formal_basetype)))
	      (return nil))))))))))


       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun sort_actuals_into_the_correct_order_if_possible (actuals formals)
       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  
  (do (
       (parampos 1)
       (aps actuals (cdr aps))
       (unsequenced nil)
       (normalized nil)
       (fps formals);returns a list of pairs.
       )
      ((null aps)
       (append (reverse normalized)
	       (sequence_kwp unsequenced fps parampos nil)))
    (ct_selectq (diana_nodetype_get (first aps))
		(dn_assoc
		  (let ((formpos (find_formal2 (first aps) fps parampos)))
		    (cond
		      ((zerop formpos) (*throw '*unmatched_keyword* nil))
		      (t (ct_push `(,formpos ,(first aps)) unsequenced)))))
		(otherwise
		  (%= fps (cdr fps))	  ; this formal is accounted for.
		  (%= parampos (1+ *_*))
;		  (ct_push (copy_dn (car aps))normalized)
		  (ct_push (car aps)normalized)))))

       ;;;;;;;;;;;;;;;;;;;;;;;;
(defun substituted_derived_type (type subst_alist)
       ;;;;;;;;;;;;;;;;;;;;;;;;
  (let ((substitution (assq type subst_alist)))
    (or (cdr substitution) type)))

       ;;;;;;;;;;;;;;;;;;;;
(defun derivable_subprogram (actt fort)
       ;;;;;;;;;;;;;;;;;;;;
  (setq actt (extract_basetype actt))
  (let ((parent_types (find_parents_of_derived_type actt))
	(for_bound (assq fort labels_alist)))
    (cond (for_bound
	   ;; this formal has been bound by a previous parameter, hereafter
	   ;; its type must be used religiously.
	   (or (eq actt (cdr for_bound))
	       (and (universal_typep actt )
		    (types_consistant_after_implicit_conversion actt fort))))
	  ((eq actt fort)
	   ;; the actual and formal match! make the binding to restrict later
	   ;; parameters in the scope of their matchability.
	   (cond ((universal_typep actt)
		  t)
		 (t (ct_push `(,fort . ,actt) labels_alist))))
	  ((memq fort parent_types)
	   ;; if the formal type is inherited by the derived type,
	   ;; we can inherit the operation provided that the formal be
	   ;; replaced by the actual type throughout the profile.
	   ;; so add the mapping to the labels_alist.
	   (cond ((universal_typep actt)
		  t)
		 (t (ct_push `(,fort . ,actt) labels_alist))))
	  ((types_consistant_after_implicit_conversion actt fort) t))))

       ;;;;;;;;;;;;;;;
(defun universal_typep (act)
       ;;;;;;;;;;;;;;;
  (memq act *universal_types*))
  
       ;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun ada_literal_or_aggregate_p (act)
       ;;;;;;;;;;;;;;;;;;;;;;;;;;
  (let ((name (strip_name act)))
    (and name
         (memq (diana_nodetype_get name)
	       '(dn_allocator
		  dn_number_id
		  dn_numeric_literal 
		  dn_string_literal
		  dn_character_literal
		  dn_null_access)))))

       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun formal_consistant_with_literalp (for lit)
       ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (setq lit (strip_name lit))
  (ct_selectq
    (diana_nodetype_get lit)
    (dn_numeric_literal
      (cond ((la_num%floatp (diana_get lit 'lx_numrep))
	     (or
	       (memq (let ((eb (extract_basetype for )))
		       (and eb (diana_nodetype_get eb)))
		     '(dn_float dn_fixed))
	       (consistant_types
		 *universal_real*
		 for
		 t)
	       (consistant_types
		 *universal_real*
		 (extract_basetype for t)
		 t)
#|	       (consistant_types
		 *universal_fixed*
		 for
		 t)|#
	       ))
	    (t
	     (or
	       (eq (let ((eb (extract_basetype for )))
		       (and eb (diana_nodetype_get eb)))
		   'dn_integer)
	       (consistant_types
		 *universal_integer*
		 (extract_basetype for t)
		 t)))))
    (dn_used_name_id
      (formal_consistant_with_literalp  for (diana_get lit 'sm_defn)))
    (dn_null_access
      (cond((null for ) nil)
	   ((eq (diana_nodetype_get for) 'dn_access)
	    t)
	   ((eq (diana_nodetype_get for) 'dn_derived)
	    (formal_consistant_with_literalp
	      (extract_basetype for t) lit))))
    (dn_string_literal
      (cond
	((null for) nil)
	((eq (diana_nodetype_get for) 'dn_array)
	 (eq (extract_basetype (diana_get for 'as_constrained) t)
	     (extract_basetype *character_type*)))))
    (dn_character_literal
      (cond ((boundp '*character_type*)
	     (consistant_types
	       *character_type*
	       for
	       t))
	    (t
	     (consistant_types
	       (ada_declared (ada_ident character) nil 'type)
	       for
	       t))))
    (dn_number_id
      (let ((obj (diana_get lit 'sm_init_exp)))
	(cond
	  ;; deferred constant?
	  ((null obj)
	   (or
	     (consistant_types
	       *universal_real*
	       for
	       t)
	     (consistant_types
	       *universal_integer*
	       for
	       t)))
	  ;; constant object definition available?
	  (t
	   (cond
	     ((eq (diana_nodetype_get obj) 'dn_function_call)
	      (consistant_types
		(extract_basetype obj)
		for
		t))
	     (t (formal_consistant_with_literalp for obj)))))))
    (dn_selected
      (formal_consistant_with_literalp for
				       (diana_get lit 'as_designator_char)))
    (dn_allocator
      (cond ((null for) nil)
	    (t (consistant_types
		 (diana_get lit 'sm_exp_type)
		 (diana_get for 'as_constrained)
		 nil))))
    (otherwise nil)))

