-------------------------------------------------------------------------------
-- (C) Altran Praxis Limited
-------------------------------------------------------------------------------
--
-- The SPARK toolset is free software; you can redistribute it and/or modify it
-- under terms of the GNU General Public License as published by the Free
-- Software Foundation; either version 3, or (at your option) any later
-- version. The SPARK toolset is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-- Public License for more details. You should have received a copy of the GNU
-- General Public License distributed with the SPARK toolset; see file
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
-- the license.
--
--=============================================================================

with E_Strings;

separate (DAG.BuildGraph)
procedure ModelProcedureCall is
   Procedure_Name_Cell : Cells.Cell;
   Concrete_Procedure  : Dictionary.Symbol;
   PrefixSym           : Dictionary.Symbol := Dictionary.NullSymbol;
   SubstitutionTable   : Cells.Cell;

   -- The interface of a procedure can have two views. An abstract view and a
   -- refined view which are denoted by the type Dictionary.Abstractions.
   -- A refined view can be defined by data refinement or proof refinement.
   -- Data refinement occurs when an own variable is refined into constituent
   -- parts and may also involve proof refinement where the pre and post
   -- conditions are in terms of the constituents.
   -- However, proof refinement may occur without data refinement to facilitate
   -- defining pre and post conditions in terms of the complete view of a
   -- private type.
   -- Hence the introduction of these two variables.
   --   Abstraction gives the view to be used for the pre and post
   --   conditions,
   --   Data_View gives the view to be used for the parameters, globals and
   --   derives annotations and from this the view of the imports and exports of
   --   the subprogram.
   Abstraction, Data_View : Dictionary.Abstractions;

   ----------------------------------------------------------

   procedure Build_Substitution_Table (Node               : in STree.SyntaxNode;
                                       Concrete_Procedure : in Dictionary.Symbol)
   --# global in     CommandLineData.Content;
   --#        in     DoAssumeLocalRvalues;
   --#        in     LineNmbr;
   --#        in     LoopStack;
   --#        in     LScope;
   --#        in     Scope;
   --#        in     STree.Table;
   --#        in out CheckStack;
   --#        in out ContainsReals;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out FlowHeap;
   --#        in out Graph.Table;
   --#        in out KindOfStackedCheck;
   --#        in out LexTokenManager.State;
   --#        in out ShortCircuitStack;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --#        in out StmtStack.S;
   --#        in out VCGFailure;
   --#        in out VCGHeap;
   --#           out SubstitutionTable;
   --# derives CheckStack,
   --#         ContainsReals,
   --#         Dictionary.Dict,
   --#         FlowHeap,
   --#         Graph.Table,
   --#         KindOfStackedCheck,
   --#         LexTokenManager.State,
   --#         ShortCircuitStack,
   --#         Statistics.TableUsage,
   --#         StmtStack.S,
   --#         VCGFailure,
   --#         VCGHeap                    from *,
   --#                                         CheckStack,
   --#                                         CommandLineData.Content,
   --#                                         Concrete_Procedure,
   --#                                         Dictionary.Dict,
   --#                                         DoAssumeLocalRvalues,
   --#                                         FlowHeap,
   --#                                         Graph.Table,
   --#                                         KindOfStackedCheck,
   --#                                         LexTokenManager.State,
   --#                                         LineNmbr,
   --#                                         LoopStack,
   --#                                         LScope,
   --#                                         Node,
   --#                                         Scope,
   --#                                         ShortCircuitStack,
   --#                                         StmtStack.S,
   --#                                         STree.Table,
   --#                                         VCGHeap &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CheckStack,
   --#                                         CommandLineData.Content,
   --#                                         Concrete_Procedure,
   --#                                         Dictionary.Dict,
   --#                                         DoAssumeLocalRvalues,
   --#                                         ErrorHandler.Error_Context,
   --#                                         FlowHeap,
   --#                                         Graph.Table,
   --#                                         KindOfStackedCheck,
   --#                                         LexTokenManager.State,
   --#                                         LineNmbr,
   --#                                         LoopStack,
   --#                                         LScope,
   --#                                         Node,
   --#                                         Scope,
   --#                                         ShortCircuitStack,
   --#                                         SPARK_IO.File_Sys,
   --#                                         StmtStack.S,
   --#                                         STree.Table,
   --#                                         VCGHeap &
   --#         SubstitutionTable          from VCGHeap;
   is
      NameArgListNode : STree.SyntaxNode;

      function Not_Mode_Out (Param_Number       : Positive;
                             Concrete_Procedure : Dictionary.Symbol) return Boolean
      --# global in Dictionary.Dict;
      is
      begin
         return Dictionary.GetSubprogramParameterMode (Dictionary.GetSubprogramParameter (Concrete_Procedure, Param_Number)) /=
           Dictionary.OutMode;
      end Not_Mode_Out;

      -----------------

      procedure Do_Positional_Association (Concrete_Procedure : in Dictionary.Symbol)
      --# global in     CommandLineData.Content;
      --#        in     DoAssumeLocalRvalues;
      --#        in     LineNmbr;
      --#        in     LoopStack;
      --#        in     LScope;
      --#        in     NameArgListNode;
      --#        in     Scope;
      --#        in     STree.Table;
      --#        in     SubstitutionTable;
      --#        in out CheckStack;
      --#        in out ContainsReals;
      --#        in out Dictionary.Dict;
      --#        in out ErrorHandler.Error_Context;
      --#        in out FlowHeap;
      --#        in out Graph.Table;
      --#        in out KindOfStackedCheck;
      --#        in out LexTokenManager.State;
      --#        in out ShortCircuitStack;
      --#        in out SPARK_IO.File_Sys;
      --#        in out Statistics.TableUsage;
      --#        in out StmtStack.S;
      --#        in out VCGFailure;
      --#        in out VCGHeap;
      --# derives CheckStack,
      --#         ContainsReals,
      --#         Dictionary.Dict,
      --#         FlowHeap,
      --#         Graph.Table,
      --#         KindOfStackedCheck,
      --#         LexTokenManager.State,
      --#         ShortCircuitStack,
      --#         Statistics.TableUsage,
      --#         StmtStack.S,
      --#         VCGFailure,
      --#         VCGHeap                    from *,
      --#                                         CheckStack,
      --#                                         CommandLineData.Content,
      --#                                         Concrete_Procedure,
      --#                                         Dictionary.Dict,
      --#                                         DoAssumeLocalRvalues,
      --#                                         FlowHeap,
      --#                                         Graph.Table,
      --#                                         KindOfStackedCheck,
      --#                                         LexTokenManager.State,
      --#                                         LineNmbr,
      --#                                         LoopStack,
      --#                                         LScope,
      --#                                         NameArgListNode,
      --#                                         Scope,
      --#                                         ShortCircuitStack,
      --#                                         StmtStack.S,
      --#                                         STree.Table,
      --#                                         SubstitutionTable,
      --#                                         VCGHeap &
      --#         ErrorHandler.Error_Context,
      --#         SPARK_IO.File_Sys          from CheckStack,
      --#                                         CommandLineData.Content,
      --#                                         Concrete_Procedure,
      --#                                         Dictionary.Dict,
      --#                                         DoAssumeLocalRvalues,
      --#                                         ErrorHandler.Error_Context,
      --#                                         FlowHeap,
      --#                                         Graph.Table,
      --#                                         KindOfStackedCheck,
      --#                                         LexTokenManager.State,
      --#                                         LineNmbr,
      --#                                         LoopStack,
      --#                                         LScope,
      --#                                         NameArgListNode,
      --#                                         Scope,
      --#                                         ShortCircuitStack,
      --#                                         SPARK_IO.File_Sys,
      --#                                         StmtStack.S,
      --#                                         STree.Table,
      --#                                         SubstitutionTable,
      --#                                         VCGHeap;
      is
         -- Builds a table using the facilities of CLists.  Each element of the list is a cell with
         -- a parameter number as its contents.  The C pointer of each list element points to a
         -- A DAG representing the actual parameter.  If there is a constraining index involved
         -- (i.e. the actual parameter is a constrained subtype of an unconstrained array) then
         -- a cell of kind ConstrainingIndex is placed between the parameter list cell and the
         -- expression DAG itself.  The structure is a bit like this:

         -- PNA experiment.  In the case of an actual parameter that is a named subtype of an
         --                  unconstrained array type then the constraint node will hold the
         --                  array subtype symbol rather than the first index subtype as originally
         --                  implemented.  Note that in the special case of a string literal actual parameter
         --                  then the constraint will still have an index type (a subtype of positive).

         --
         -- SubstitutionTable -> 1 -> 2 -> 3 -> etc
         --                      |    |    |
         --                      v    v    v
         --                     dag  dag  constraint
         --                                |
         --                                v
         --                               dag

         ParamCounter            : Positive;
         TryNode                 : STree.SyntaxNode;
         ListElement, Expression : Cells.Cell;
         ConstraintCell          : Cells.Cell;
         ConstraintIndex         : Dictionary.Symbol;
      begin
         ParamCounter := 1;
         TryNode      := NameArgListNode;
         while STree.Syntax_Node_Type (Node => TryNode) /= SP_Symbols.expression loop
            TryNode := STree.Child_Node (Current_Node => TryNode);
         end loop;
         -- TryNode is now bottommost expression ie. first parameter
         while TryNode /= STree.NullNode loop
            ConstraintCell := Cells.Null_Cell;
            Cells.Create_Cell (VCGHeap, ListElement);
            Cells.Set_Natural_Value (VCGHeap, ListElement, ParamCounter);

            BuildExpnDAG
              (TryNode,
               LScope,
               Scope,
               LineNmbr,
               True,
               DoAssumeLocalRvalues
                 and then Not_Mode_Out (Param_Number       => ParamCounter,
                                        Concrete_Procedure => Concrete_Procedure),
               LoopStack,
               FlowHeap,
               VCGHeap,
               ContainsReals,
               VCGFailure,
               ShortCircuitStack,
               CheckStack,
               KindOfStackedCheck,
               -- to get
               Expression);

            -- Constraining index (if there is one) will have been planted at expression node by wffs

            ConstraintIndex := STree.NodeSymbol (TryNode);
            if not Dictionary.Is_Null_Symbol (ConstraintIndex) then
               CreateCellKind (ConstraintCell, VCGHeap, Cell_Storage.Constraining_Index);
               Cells.Set_Symbol_Value (VCGHeap, ConstraintCell, ConstraintIndex);
               -- PNA unchnaged name at present, but "Index" is misleading now
            end if;

            -- We may need to convert the actual parameter by inserting some inherit
            -- derefences in front of it; conversion is required if we have called
            -- an inherited root function.  The parameter in this case must be an
            -- object.
            ConvertTaggedActualIfNecessary (Concrete_Procedure, VCGHeap, Expression);

            -- Link constraint (if any) and DAG into linked list of parameters
            if Cells.Is_Null_Cell (ConstraintCell) then
               SetAuxPtr (ListElement, Expression, VCGHeap);
            else
               SetAuxPtr (ListElement, ConstraintCell, VCGHeap);
               SetAuxPtr (ConstraintCell, Expression, VCGHeap);
            end if;
            Clists.InsertCell (VCGHeap, ListElement, SubstitutionTable);
            ParamCounter := ParamCounter + 1;
            TryNode      := STree.Next_Sibling (Current_Node => STree.Parent_Node (Current_Node => TryNode));
         end loop;
      end Do_Positional_Association;

      -------------------------------------------------------------

      procedure Do_Named_Association (Concrete_Procedure : in Dictionary.Symbol)
      --# global in     CommandLineData.Content;
      --#        in     DoAssumeLocalRvalues;
      --#        in     LineNmbr;
      --#        in     LoopStack;
      --#        in     LScope;
      --#        in     NameArgListNode;
      --#        in     Scope;
      --#        in     STree.Table;
      --#        in     SubstitutionTable;
      --#        in out CheckStack;
      --#        in out ContainsReals;
      --#        in out Dictionary.Dict;
      --#        in out ErrorHandler.Error_Context;
      --#        in out FlowHeap;
      --#        in out Graph.Table;
      --#        in out KindOfStackedCheck;
      --#        in out LexTokenManager.State;
      --#        in out ShortCircuitStack;
      --#        in out SPARK_IO.File_Sys;
      --#        in out Statistics.TableUsage;
      --#        in out StmtStack.S;
      --#        in out VCGFailure;
      --#        in out VCGHeap;
      --# derives CheckStack,
      --#         ContainsReals,
      --#         Dictionary.Dict,
      --#         FlowHeap,
      --#         Graph.Table,
      --#         KindOfStackedCheck,
      --#         LexTokenManager.State,
      --#         ShortCircuitStack,
      --#         Statistics.TableUsage,
      --#         StmtStack.S,
      --#         VCGFailure,
      --#         VCGHeap                    from *,
      --#                                         CheckStack,
      --#                                         CommandLineData.Content,
      --#                                         Concrete_Procedure,
      --#                                         Dictionary.Dict,
      --#                                         DoAssumeLocalRvalues,
      --#                                         FlowHeap,
      --#                                         Graph.Table,
      --#                                         KindOfStackedCheck,
      --#                                         LexTokenManager.State,
      --#                                         LineNmbr,
      --#                                         LoopStack,
      --#                                         LScope,
      --#                                         NameArgListNode,
      --#                                         Scope,
      --#                                         ShortCircuitStack,
      --#                                         StmtStack.S,
      --#                                         STree.Table,
      --#                                         SubstitutionTable,
      --#                                         VCGHeap &
      --#         ErrorHandler.Error_Context,
      --#         SPARK_IO.File_Sys          from CheckStack,
      --#                                         CommandLineData.Content,
      --#                                         Concrete_Procedure,
      --#                                         Dictionary.Dict,
      --#                                         DoAssumeLocalRvalues,
      --#                                         ErrorHandler.Error_Context,
      --#                                         FlowHeap,
      --#                                         Graph.Table,
      --#                                         KindOfStackedCheck,
      --#                                         LexTokenManager.State,
      --#                                         LineNmbr,
      --#                                         LoopStack,
      --#                                         LScope,
      --#                                         NameArgListNode,
      --#                                         Scope,
      --#                                         ShortCircuitStack,
      --#                                         SPARK_IO.File_Sys,
      --#                                         StmtStack.S,
      --#                                         STree.Table,
      --#                                         SubstitutionTable,
      --#                                         VCGHeap;
      is
         -- See comment in Do_Positional_Association above for the purpose of this procedure.
         ParamCounter            : Positive;
         TryNode                 : STree.SyntaxNode;
         ListElement, Expression : Cells.Cell;
         ConstraintCell          : Cells.Cell;
         ConstraintIndex         : Dictionary.Symbol;

         -------------------------------------------------------

         procedure GetParamNumber (Name    : in     LexTokenManager.Lex_String;
                                   ProcSym : in     Dictionary.Symbol;
                                   ParamNo :    out Positive)
         --# global in Dictionary.Dict;
         --#        in LexTokenManager.State;
         --# derives ParamNo from Dictionary.Dict,
         --#                      LexTokenManager.State,
         --#                      Name,
         --#                      ProcSym;
         is
            It  : Dictionary.Iterator;
            Sym : Dictionary.Symbol;

         begin
            It := Dictionary.FirstSubprogramParameter (ProcSym);
            SystemErrors.RT_Assert
              (C       => not Dictionary.IsNullIterator (It),
               Sys_Err => SystemErrors.Precondition_Failure,
               Msg     => "Can't find first parameter in BuildGraph.ModelProcedureCall.GetParamNumber");
            loop
               Sym := Dictionary.CurrentSymbol (It);
               exit when LexTokenManager.Lex_String_Case_Insensitive_Compare
                 (Lex_Str1 => Dictionary.GetSimpleName (Sym),
                  Lex_Str2 => Name) =
                 LexTokenManager.Str_Eq;
               It := Dictionary.NextSymbol (It);
               exit when Dictionary.IsNullIterator (It);
            end loop;
            ParamNo := Dictionary.GetSubprogramParameterNumber (Sym);
         end GetParamNumber;

      begin -- Do_Named_Association
         TryNode := NameArgListNode;
         while STree.Syntax_Node_Type (Node => TryNode) /= SP_Symbols.simple_name loop
            TryNode := STree.Child_Node (Current_Node => TryNode);
         end loop;
         -- TryNode is now simple_name of first parameter
         while TryNode /= STree.NullNode loop
            ConstraintCell := Cells.Null_Cell;
            Cells.Create_Cell (VCGHeap, ListElement);
            GetParamNumber
              (STree.Node_Lex_String (Node => STree.Child_Node (Current_Node => TryNode)),
               Concrete_Procedure,
               -- to get
               ParamCounter);
            Cells.Set_Natural_Value (VCGHeap, ListElement, ParamCounter);
            BuildExpnDAG
              (STree.Next_Sibling (Current_Node => TryNode),
               LScope,
               Scope,
               LineNmbr,
               True,
               DoAssumeLocalRvalues
                 and then Not_Mode_Out (Param_Number       => ParamCounter,
                                        Concrete_Procedure => Concrete_Procedure),
               -- assume rvalues only for in/inout params
               LoopStack,
               FlowHeap,
               VCGHeap,
               ContainsReals,
               VCGFailure,
               ShortCircuitStack,
               CheckStack,
               KindOfStackedCheck,
               -- to get
               Expression);

            -- Constraining index (if there is one) will have been planted at expression node by wffs
            ConstraintIndex := STree.NodeSymbol (STree.Next_Sibling (Current_Node => TryNode));
            if not Dictionary.Is_Null_Symbol (ConstraintIndex) then
               CreateCellKind (ConstraintCell, VCGHeap, Cell_Storage.Constraining_Index);
               Cells.Set_Symbol_Value (VCGHeap, ConstraintCell, ConstraintIndex);
            end if;

            -- We may need to convert the actual parameter by inserting some inherit
            -- derefences in front of it; conversion is required if we have called
            -- an inherited root function.  The parameter in this case must be an
            -- object.
            ConvertTaggedActualIfNecessary (Concrete_Procedure, VCGHeap, Expression);

            -- Link constraint (if any) and DAG into linked list of parameters
            if Cells.Is_Null_Cell (ConstraintCell) then
               SetAuxPtr (ListElement, Expression, VCGHeap);
            else
               SetAuxPtr (ListElement, ConstraintCell, VCGHeap);
               SetAuxPtr (ConstraintCell, Expression, VCGHeap);
            end if;
            Clists.InsertCell (VCGHeap, ListElement, SubstitutionTable);
            TryNode := STree.Next_Sibling (Current_Node => STree.Parent_Node (Current_Node => TryNode));
         end loop;
      end Do_Named_Association;

   begin -- Build_Substitution_Table

      -- Node is procedure_call_statement
      Clists.CreateList (VCGHeap, SubstitutionTable);
      NameArgListNode :=
        STree.Next_Sibling (Current_Node => STree.Child_Node (Current_Node => STree.Child_Node (Current_Node => Node)));
      if NameArgListNode /= STree.NullNode then
         if STree.Syntax_Node_Type (Node => STree.Child_Node (Current_Node => NameArgListNode)) =
           SP_Symbols.positional_argument_association then
            Do_Positional_Association (Concrete_Procedure => Concrete_Procedure);
         else
            Do_Named_Association (Concrete_Procedure => Concrete_Procedure);
         end if;
      end if;
   end Build_Substitution_Table;

   ----------------------------------------------------------

   function GetExpressionCell (Parameter : Positive) return Cells.Cell
   --# global in SubstitutionTable;
   --#        in VCGHeap;
   is
      -- For a particular parameter number, find the DAG associated with the actual parameter
      -- expression.  This will be found in the substitution table built by procedure Build_Substitution_Table
      Try : Cells.Cell;
   begin
      Try := Clists.FirstCell (VCGHeap, SubstitutionTable);
      while Cells.Get_Natural_Value (VCGHeap, Try) /= Parameter loop
         Try := Clists.NextCell (VCGHeap, Try);
      end loop;
      Try := AuxPtr (VCGHeap, Try);
      if Cells.Get_Kind (VCGHeap, Try) = Cell_Storage.Constraining_Index then
         -- expression is one lower in the data strucure - see comment in Do_Positional_Association above
         Try := AuxPtr (VCGHeap, Try);
      end if;
      return Try;
   end GetExpressionCell;

   ----------------------------------------------------------

   function GetConstraintCell (Parameter : Positive) return Cells.Cell
   --# global in SubstitutionTable;
   --#        in VCGHeap;
   is
      -- This is similar to GetExpressionCell but returns the constraining index cell if there is one otherwise
      -- it returns the actual parameter expression's DAG.
      Try : Cells.Cell;
   begin
      Try := Clists.FirstCell (VCGHeap, SubstitutionTable);
      while Cells.Get_Natural_Value (VCGHeap, Try) /= Parameter loop
         Try := Clists.NextCell (VCGHeap, Try);
      end loop;
      return AuxPtr (VCGHeap, Try);
   end GetConstraintCell;

   ----------------------------------------------------------
   -- There are several places below where we need to traverse a DAG that contains
   -- record field selections and/or array element references.  The following two functions
   -- simplify this search process

   function IsSelector (The_Cell : Cells.Cell) return Boolean
   --# global in VCGHeap;
   is
   begin
      return Cells.Get_Kind (VCGHeap, The_Cell) = Cell_Storage.Field_Access_Function
        or else Cells.Get_Kind (VCGHeap, The_Cell) = Cell_Storage.Element_Function;
   end IsSelector;

   -- a field selector function has the form:
   -- fld_name --- expression
   --
   -- an array element function has the form
   -- element --- , --- index
   --             |
   --          expression
   function ArgumentOfSelector (The_Cell : Cells.Cell) return Cells.Cell
   --# global in VCGHeap;
   is
      Result : Cells.Cell;
   begin
      if Cells.Get_Kind (VCGHeap, The_Cell) = Cell_Storage.Field_Access_Function then
         -- for a record field access, the expression is to the right
         Result := RightPtr (VCGHeap, The_Cell);
      else -- must be element function because of precondition

         -- for an array access, we have a comma to the right and the expression to the left of this
         Result := LeftPtr (VCGHeap, RightPtr (VCGHeap, The_Cell));
      end if;
      return Result;
   end ArgumentOfSelector;

   ----------------------------------------------------------
   -- Given a symbol for an export which is either the symbol of a global
   -- variable or the symbol of a formal parameter, this procedure returns
   -- the symbol of the entire variable being exported and the DAG that
   -- represents the actual parameter expression.
   -- If the export is a global then Entire_Actual_Sym = Formal_Or_Global_Sym and
   -- Actual_DAG = Cells.Null_Cell.  For parameters the substitution table is used
   -- to obtain the returned results.
   procedure Get_Export_Details
     (Formal_Or_Global_Sym : in     Dictionary.Symbol;
      Concrete_Procedure   : in     Dictionary.Symbol;
      Entire_Actual_Sym    :    out Dictionary.Symbol;
      Actual_DAG           :    out Cells.Cell)
   --# global in Dictionary.Dict;
   --#        in PrefixSym;
   --#        in SubstitutionTable;
   --#        in VCGHeap;
   --# derives Actual_DAG        from Concrete_Procedure,
   --#                                Dictionary.Dict,
   --#                                Formal_Or_Global_Sym,
   --#                                SubstitutionTable,
   --#                                VCGHeap &
   --#         Entire_Actual_Sym from Concrete_Procedure,
   --#                                Dictionary.Dict,
   --#                                Formal_Or_Global_Sym,
   --#                                PrefixSym,
   --#                                SubstitutionTable,
   --#                                VCGHeap;
   is
      Actual_DAG_Local        : Cells.Cell;
      Entire_Actual_Sym_Local : Dictionary.Symbol;

      ----------------------------------------------------------

      function Substitute_Protected_Type_Self_Reference (Sym, Prefix_Symbol : Dictionary.Symbol) return Dictionary.Symbol
      --# global in Dictionary.Dict;
      is
         Result : Dictionary.Symbol;
      begin
         -- if Sym is the implicitly-declared own variable of a protected type
         -- then we must replace it with the "current instance of the protected object"
         -- before checking whether it is visible.
         -- Background: given protected type PT its operations will globally reference and
         -- derive PT meaning, in this case, "myself".
         -- If an object PO of type PT (or a subtype of PT) is declared then calls to its
         -- operations will take the form PO.Op and the calling environment will be annotated
         -- in terms of PO.  Therefore, when checking that the globals necessary for the call
         -- PO.Op are visible (for example), we need to replace all references to PT into
         -- references to PO before making the check.  The Prefix Symbol of the call is the
         -- symbol we need to substitute in.
         Result := Sym;
         if not Dictionary.Is_Null_Symbol (Prefix_Symbol)
           and then Dictionary.IsOwnVariable (Sym)
           and then Dictionary.IsProtectedType (Dictionary.GetOwner (Sym)) then
            Result := Prefix_Symbol;
         end if;
         return Result;
      end Substitute_Protected_Type_Self_Reference;

   begin  -- Get_Export_Details
      if Dictionary.IsFormalParameter (Concrete_Procedure, Formal_Or_Global_Sym) then
         Actual_DAG_Local := GetExpressionCell (Dictionary.GetSubprogramParameterNumber (Formal_Or_Global_Sym));

         Actual_DAG := Actual_DAG_Local;
         while IsSelector (Actual_DAG_Local) loop
            Actual_DAG_Local := ArgumentOfSelector (Actual_DAG_Local);
         end loop;
         Entire_Actual_Sym_Local := Cells.Get_Symbol_Value (VCGHeap, Actual_DAG_Local);
      else
         Entire_Actual_Sym_Local := Formal_Or_Global_Sym;
         Actual_DAG              := Cells.Null_Cell;
      end if;
      -- if the export is from a protected procedure it may ba type name (representing "this") rather
      -- than the protected object itself; the following substitutes the PO name.
      Entire_Actual_Sym := Substitute_Protected_Type_Self_Reference (Sym           => Entire_Actual_Sym_Local,
                                                                     Prefix_Symbol => PrefixSym);
   end Get_Export_Details;

   ----------------------------------------------------------
   procedure Substitute_Import
     (Sym                : in     Dictionary.Symbol;
      Concrete_Procedure : in     Dictionary.Symbol;
      Change             :    out Boolean;
      Result             :    out Cells.Cell)
   --# global in Dictionary.Dict;
   --#        in SubstitutionTable;
   --#        in VCGHeap;
   --# derives Change from Concrete_Procedure,
   --#                     Dictionary.Dict,
   --#                     Sym &
   --#         Result from Concrete_Procedure,
   --#                     Dictionary.Dict,
   --#                     SubstitutionTable,
   --#                     Sym,
   --#                     VCGHeap;
   is
      -- Given the Symbol of an import, replaces it with the matching actual parameter expression
      -- (if a formal parameter) otherwise does nothing.  Change is set to True if a substitution has been made
   begin
      if Dictionary.IsFormalParameter (Concrete_Procedure, Sym) then
         Change := True;
         Result := GetExpressionCell (Dictionary.GetSubprogramParameterNumber (Sym));
      else
         Result := Cells.Null_Cell;
         Change := False;
      end if;
   end Substitute_Import;

   ---------------------------------------------------------------------

   procedure Substitute_Import_Constraint
     (Sym                : in     Dictionary.Symbol;
      Concrete_Procedure : in     Dictionary.Symbol;
      Change             :    out Boolean;
      Result             :    out Cells.Cell)
   --# global in     Dictionary.Dict;
   --#        in     SubstitutionTable;
   --#        in out Statistics.TableUsage;
   --#        in out VCGHeap;
   --# derives Change                from Concrete_Procedure,
   --#                                    Dictionary.Dict,
   --#                                    Sym &
   --#         Result                from Concrete_Procedure,
   --#                                    Dictionary.Dict,
   --#                                    Sym,
   --#                                    VCGHeap &
   --#         Statistics.TableUsage from *,
   --#                                    Concrete_Procedure,
   --#                                    Dictionary.Dict,
   --#                                    Sym,
   --#                                    VCGHeap &
   --#         VCGHeap               from *,
   --#                                    Concrete_Procedure,
   --#                                    Dictionary.Dict,
   --#                                    SubstitutionTable,
   --#                                    Sym;
   is
      -- Similar to Substitute_Import above but returns the constraining index type associated with
      -- a constrained actual parameter associated with an unconstrained formal parameter
      ConstraintSym  : Dictionary.Symbol;
      ObjectSym      : Dictionary.Symbol;
      ArrayDimension : Positive;
   begin
      -- The Sym passed to this routine will be a Dictionary.ParameterConstraintSymbol.
      -- From this we can obtain the object itself and the dimesnion of that object that appears
      -- in the expression we may be making substitutions to.
      ObjectSym      := Dictionary.GetParameterAssociatedWithParameterConstraint (Sym);
      ArrayDimension := Dictionary.GetSubprogramParameterConstraintDimension (Sym);

      if Dictionary.IsFormalParameter (Concrete_Procedure, ObjectSym) then
         Change := True;
         Cells.Create_Cell (VCGHeap, Result);
         Cells.Copy_Contents (VCGHeap, GetConstraintCell (Dictionary.GetSubprogramParameterNumber (ObjectSym)), Result);
         -- Result contains either:
         -- (1) an array subtype symbol in the case where the actual paramater is of a constrained
         --     array subtype
         -- (2) a scalar index type symbol in the case of a string literal being passed to string
         -- (3) a symbol of a subprogram parameter in the case where the actual parameter is also
         --     an unconstrained array and no constraint has been planted (this final behaviour occurs
         --     because GetConstraintCell returns the actual parameter DAG if no constraint is present)
         ConstraintSym := Cells.Get_Symbol_Value (VCGHeap, Result);
         if Dictionary.IsSubprogramParameter (ConstraintSym) then
            -- Case 3.  We substitute "actual__index__subtype__n" for "formal__index__subtype__n"
            Cells.Set_Symbol_Value (VCGHeap, Result, Dictionary.GetSubprogramParameterConstraint (ConstraintSym, ArrayDimension));

         elsif Dictionary.TypeIsArray (ConstraintSym) then
            -- Case 2. We substitute array index n of constraining subtype for "formal__index__subtype__n"
            Cells.Set_Symbol_Value (VCGHeap, Result, Dictionary.GetArrayIndex (ConstraintSym, ArrayDimension));
         else
            -- Case 1. we already have the constraining index directly
            null;
         end if;
      else
         Result := Cells.Null_Cell;
         Change := False;
      end if;
   end Substitute_Import_Constraint;

   ---------------------------------------------------------------------
   -- procedure to create modelling vars for procedure export
   procedure Convert_Cell_To_Export_Cell (Cell_Name          : in Cells.Cell;
                                          Concrete_Procedure : in Dictionary.Symbol)
   --# global in     Dictionary.Dict;
   --#        in     PrefixSym;
   --#        in     SubprogramCalls;
   --#        in     SubstitutionTable;
   --#        in out LexTokenManager.State;
   --#        in out Statistics.TableUsage;
   --#        in out VCGHeap;
   --# derives LexTokenManager.State from *,
   --#                                    SubprogramCalls &
   --#         Statistics.TableUsage from *,
   --#                                    Cell_Name,
   --#                                    Concrete_Procedure,
   --#                                    Dictionary.Dict,
   --#                                    SubstitutionTable,
   --#                                    VCGHeap &
   --#         VCGHeap               from *,
   --#                                    Cell_Name,
   --#                                    Concrete_Procedure,
   --#                                    Dictionary.Dict,
   --#                                    LexTokenManager.State,
   --#                                    PrefixSym,
   --#                                    SubprogramCalls,
   --#                                    SubstitutionTable;
   is
      Count_Str                              : LexTokenManager.Lex_String;
      Cell_Name_Local, Temp_Cell, Export_DAG : Cells.Cell;
      ExportSym                              : Dictionary.Symbol;
   begin
      -- if the cell supplied is simply a variable we convert the cell sort to
      -- a procedure export variable adding in the necessary call counter.  If
      -- it is the top of a DAG containing record field references we convert the
      -- cell which represents the entire record variable after making a copy
      -- of the actual DAG.
      LexTokenManager.Insert_Nat (N       => SubprogramCalls,
                                  Lex_Str => Count_Str);
      Get_Export_Details
        (Formal_Or_Global_Sym => Cells.Get_Symbol_Value (VCGHeap, Cell_Name),
         Concrete_Procedure   => Concrete_Procedure,
         Entire_Actual_Sym    => ExportSym,
         Actual_DAG           => Export_DAG);

      -- see if there is an Export DAG representing a fld access of a record
      -- variable or an array element function.
      if not Cells.Is_Null_Cell (Export_DAG)
        and then (Cells.Get_Kind (VCGHeap, Export_DAG) = Cell_Storage.Field_Access_Function
                    or else Cells.Get_Kind (VCGHeap, Export_DAG) = Cell_Storage.Element_Function) then
         -- field access or array element access found we must substitute input node with
         -- the export DAG and converting the entire variable concerned to an export
         -- variable.
         Structures.CopyStructure (VCGHeap, Export_DAG, Cell_Name_Local);
         Cells.Copy_Contents (VCGHeap, Cell_Name_Local, Cell_Name);
         Temp_Cell := Cell_Name;
         while IsSelector (Temp_Cell) loop
            Temp_Cell := ArgumentOfSelector (Temp_Cell);
         end loop;
         -- Temp_Cell now points at entire variable cell
         Cells.Set_Kind (VCGHeap, Temp_Cell, Cell_Storage.Procedure_Export);
         Cells.Set_Lex_Str (VCGHeap, Temp_Cell, Count_Str);

      else
         --  no FieldAccess found so export is an entire variable.
         --  Just convert cell directly to an export cell as before
         --  and put in the symbol of the actual export
         Cells.Set_Kind (VCGHeap, Cell_Name, Cell_Storage.Procedure_Export);
         Cells.Set_Symbol_Value (VCGHeap, Cell_Name, ExportSym);
         Cells.Set_Lex_Str (VCGHeap, Cell_Name, Count_Str);
      end if;

   end Convert_Cell_To_Export_Cell;

   ---------------------------------------------------------------------

   -- The view of the precondition, abstract or refined is determined by the parameter Abstraction
   procedure Model_Precondition (Abstraction        : in Dictionary.Abstractions;
                                 Concrete_Procedure : in Dictionary.Symbol)
   --# global in     CommandLineData.Content;
   --#        in     LoopStack;
   --#        in     Scope;
   --#        in     STree.Table;
   --#        in     SubstitutionTable;
   --#        in out CheckStack;
   --#        in out ContainsReals;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out Graph.Table;
   --#        in out KindOfStackedCheck;
   --#        in out LexTokenManager.State;
   --#        in out ShortCircuitStack;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --#        in out StmtStack.S;
   --#        in out VCGFailure;
   --#        in out VCGHeap;
   --# derives CheckStack,
   --#         ContainsReals,
   --#         ShortCircuitStack,
   --#         Statistics.TableUsage,
   --#         VCGHeap                    from *,
   --#                                         Abstraction,
   --#                                         CheckStack,
   --#                                         CommandLineData.Content,
   --#                                         Concrete_Procedure,
   --#                                         Dictionary.Dict,
   --#                                         Graph.Table,
   --#                                         LexTokenManager.State,
   --#                                         LoopStack,
   --#                                         Scope,
   --#                                         ShortCircuitStack,
   --#                                         StmtStack.S,
   --#                                         STree.Table,
   --#                                         SubstitutionTable,
   --#                                         VCGHeap &
   --#         Dictionary.Dict,
   --#         LexTokenManager.State,
   --#         VCGFailure                 from *,
   --#                                         Abstraction,
   --#                                         CommandLineData.Content,
   --#                                         Concrete_Procedure,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         LoopStack,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         VCGHeap &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from Abstraction,
   --#                                         CommandLineData.Content,
   --#                                         Concrete_Procedure,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         LoopStack,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         VCGHeap &
   --#         Graph.Table,
   --#         StmtStack.S                from Abstraction,
   --#                                         CommandLineData.Content,
   --#                                         Concrete_Procedure,
   --#                                         Dictionary.Dict,
   --#                                         Graph.Table,
   --#                                         LexTokenManager.State,
   --#                                         LoopStack,
   --#                                         Scope,
   --#                                         StmtStack.S,
   --#                                         STree.Table,
   --#                                         SubstitutionTable,
   --#                                         VCGHeap &
   --#         KindOfStackedCheck         from *,
   --#                                         Abstraction,
   --#                                         Concrete_Procedure,
   --#                                         Dictionary.Dict;
   is
      Instantiated_Subprogram : Dictionary.Symbol;
      Local_Abstraction       : Dictionary.Abstractions;
      Constraint              : STree.SyntaxNode;
      DAG_Cell                : Cells.Cell;
      Conjoined_Function_Defs : Cells.Cell;
      Function_Defs           : CStacks.Stack;

      --------------------------------------------

      procedure Substitute_Parameters (Constraint_Root    : in Cells.Cell;
                                       Concrete_Procedure : in Dictionary.Symbol)
      -- replace formal parameters by actual ones in a subprogram constraint;
      --# global in     Dictionary.Dict;
      --#        in     SubstitutionTable;
      --#        in out Statistics.TableUsage;
      --#        in out VCGHeap;
      --# derives Statistics.TableUsage,
      --#         VCGHeap               from *,
      --#                                    Concrete_Procedure,
      --#                                    Constraint_Root,
      --#                                    Dictionary.Dict,
      --#                                    SubstitutionTable,
      --#                                    VCGHeap;
      is
         Subs, P : Cells.Cell;
         S       : CStacks.Stack;
         VarSym  : Dictionary.Symbol;
         Change  : Boolean;
      begin
         -- DAG traversal algorithm of D.E. Knuth, Fundamental Algorithms, p.317;
         CStacks.CreateStack (S);
         Subs := Cells.Null_Cell; -- to avoid conditional DFA later
         P    := Constraint_Root;
         loop
            loop
               exit when Cells.Is_Null_Cell (P);
               CStacks.Push (VCGHeap, P, S);
               if Is_Leaf (Node     => P,
                           VCG_Heap => VCGHeap) then
                  P := Cells.Null_Cell;
               else
                  P := LeftPtr (VCGHeap, P);
               end if;
            end loop;
            exit when CStacks.IsEmpty (S);
            P := CStacks.Top (VCGHeap, S);
            CStacks.Pop (VCGHeap, S);
            if Is_Leaf (Node     => P,
                        VCG_Heap => VCGHeap) then
               Change := False;
               VarSym := Cells.Get_Symbol_Value (VCGHeap, P);
               if Cells.Get_Kind (VCGHeap, P) = Cell_Storage.Reference then
                  Substitute_Import (Sym                => VarSym,
                                     Concrete_Procedure => Concrete_Procedure,
                                     Change             => Change,
                                     Result             => Subs);
               elsif Cells.Get_Kind (VCGHeap, P) = Cell_Storage.Unconstrained_Attribute_Prefix then
                  Substitute_Import_Constraint
                    (Sym                => VarSym,
                     Concrete_Procedure => Concrete_Procedure,
                     Change             => Change,
                     Result             => Subs);
               end if;
               if Change then
                  Cells.Copy_Contents (VCGHeap, Subs, P);
               end if;
               P := Cells.Null_Cell;
            else
               P := RightPtr (VCGHeap, P);
            end if;
         end loop;
      end Substitute_Parameters;

      procedure Check_Type_Of_Actual_Import_Params (Concrete_Procedure : in Dictionary.Symbol)
      --# global in     Dictionary.Dict;
      --#        in     Scope;
      --#        in     SubstitutionTable;
      --#        in out CheckStack;
      --#        in out ContainsReals;
      --#        in out ShortCircuitStack;
      --#        in out Statistics.TableUsage;
      --#        in out VCGHeap;
      --# derives CheckStack,
      --#         ContainsReals,
      --#         ShortCircuitStack,
      --#         Statistics.TableUsage,
      --#         VCGHeap               from *,
      --#                                    CheckStack,
      --#                                    Concrete_Procedure,
      --#                                    Dictionary.Dict,
      --#                                    Scope,
      --#                                    ShortCircuitStack,
      --#                                    SubstitutionTable,
      --#                                    VCGHeap;
      is
         ParamElement : Cells.Cell;
         ParamNum     : Natural;
         ActualParam  : Cells.Cell;
         FormalParam  : Dictionary.Symbol;
      begin
         ParamNum     := 1;
         ParamElement := Clists.FirstCell (VCGHeap, SubstitutionTable);

         while not Cells.Is_Null_Cell (ParamElement) loop
            ActualParam := AuxPtr (VCGHeap, ParamElement);
            FormalParam := Dictionary.GetSubprogramParameter (Concrete_Procedure, ParamNum);
            -- Formal parameters are always defined in the abstract view and cannot be refined
            -- and so we should always consider the abstract view.
            if Dictionary.IsImport (Dictionary.IsAbstract, Concrete_Procedure, FormalParam) then
               CheckConstraintRunTimeError
                 (Dictionary.GetType (FormalParam),
                  ActualParam,
                  Scope,
                  VCGHeap,
                  ShortCircuitStack,
                  CheckStack,
                  ContainsReals);
            end if;

            ParamElement := Clists.NextCell (VCGHeap, ParamElement);
            ParamNum     := ParamNum + 1;
         end loop;
      end Check_Type_Of_Actual_Import_Params;

   begin -- Model_Precondition

      if Dictionary.IsInstantiation (Concrete_Procedure) then
         Instantiated_Subprogram := Concrete_Procedure;
         Local_Abstraction       := Dictionary.IsAbstract;
      else -- not generic
         Instantiated_Subprogram := Dictionary.NullSymbol;
         Local_Abstraction       := Abstraction;
      end if;

      Constraint := STree.RefToNode (Dictionary.GetPrecondition (Local_Abstraction, Concrete_Procedure));
      if Constraint /= STree.NullNode then
         -- Initialize the function definition stack
         CStacks.CreateStack (Function_Defs);

         Build_Annotation_Expression
           (Exp_Node                         => Constraint,
            Instantiated_Subprogram          => Instantiated_Subprogram,
            Scope                            => Dictionary.Set_Visibility (The_Visibility => Dictionary.Local,
                                                                           The_Unit       => Concrete_Procedure),
            Calling_Scope                    => Scope,
            Force_Abstract                   => Abstraction = Dictionary.IsAbstract,
            Loop_Stack                       => LoopStack,
            Generate_Function_Instantiations => True,
            VC_Failure                       => VCGFailure,
            VC_Contains_Reals                => ContainsReals,
            VCG_Heap                         => VCGHeap,
            DAG_Root                         => DAG_Cell,
            Function_Defs                    => Function_Defs);

         if not CStacks.IsEmpty (Function_Defs) then
            -- Functions are called within the procedure's pre condition
            -- Use null statement as place holder for the function definitions
            ModelNullStmt (VCGHeap);

            -- Conjoin all the function definitions on the stack
            --# accept F, 10, Function_Defs, "The stack has been emptied";
            Join_And (Stack    => Function_Defs,
                      Conjunct => Conjoined_Function_Defs,
                      VCG_Heap => VCGHeap);
            --# end accept;

            -- Use the actual parameters of the procedure call in the function
            -- definitions.
            Substitute_Parameters (Constraint_Root    => Conjoined_Function_Defs,
                                   Concrete_Procedure => Concrete_Procedure);

            -- Assume the function definitions from the point of the null statement
            IncorporateAssumption (VCGHeap, Conjoined_Function_Defs);
         end if;

         -- Substitute the actual parameters for the formal nes in the
         -- procedure's precondition
         Substitute_Parameters (Constraint_Root    => DAG_Cell,
                                Concrete_Procedure => Concrete_Procedure);

         StackCheckStatement (DAG_Cell, VCGHeap, CheckStack);
         KindOfStackedCheck := Graph.Precon_Check;
      end if;
      Check_Type_Of_Actual_Import_Params (Concrete_Procedure => Concrete_Procedure);
   end Model_Precondition;

   --------------------------------------------------------------------------

   -- Abstraction gives the view of the postcondition to be used and Data_View gives the view of
   -- the Imports and Exports to be used
   procedure Model_Postcondition
     (Abstraction, Data_View : in Dictionary.Abstractions;
      Concrete_Procedure     : in Dictionary.Symbol;
      Scope                  : in Dictionary.Scopes)
   --# global in     CommandLineData.Content;
   --#        in     LoopStack;
   --#        in     PrefixSym;
   --#        in     STree.Table;
   --#        in     SubprogramCalls;
   --#        in     SubstitutionTable;
   --#        in out ContainsReals;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out Graph.Table;
   --#        in out LexTokenManager.State;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --#        in out StmtStack.S;
   --#        in out VCGFailure;
   --#        in out VCGHeap;
   --# derives ContainsReals,
   --#         Dictionary.Dict,
   --#         VCGFailure                 from *,
   --#                                         Abstraction,
   --#                                         CommandLineData.Content,
   --#                                         Concrete_Procedure,
   --#                                         Data_View,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         LoopStack,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         VCGHeap &
   --#         ErrorHandler.Error_Context from *,
   --#                                         Abstraction,
   --#                                         CommandLineData.Content,
   --#                                         Concrete_Procedure,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         LoopStack,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         VCGHeap &
   --#         Graph.Table,
   --#         StmtStack.S,
   --#         VCGHeap                    from Abstraction,
   --#                                         CommandLineData.Content,
   --#                                         Concrete_Procedure,
   --#                                         Data_View,
   --#                                         Dictionary.Dict,
   --#                                         Graph.Table,
   --#                                         LexTokenManager.State,
   --#                                         LoopStack,
   --#                                         PrefixSym,
   --#                                         Scope,
   --#                                         StmtStack.S,
   --#                                         STree.Table,
   --#                                         SubprogramCalls,
   --#                                         SubstitutionTable,
   --#                                         VCGHeap &
   --#         LexTokenManager.State,
   --#         Statistics.TableUsage      from *,
   --#                                         Abstraction,
   --#                                         CommandLineData.Content,
   --#                                         Concrete_Procedure,
   --#                                         Data_View,
   --#                                         Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         LoopStack,
   --#                                         PrefixSym,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         SubprogramCalls,
   --#                                         SubstitutionTable,
   --#                                         VCGHeap &
   --#         SPARK_IO.File_Sys          from *,
   --#                                         Abstraction,
   --#                                         CommandLineData.Content,
   --#                                         Concrete_Procedure,
   --#                                         Data_View,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         LoopStack,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         VCGHeap;
   is
      Instantiated_Subprogram : Dictionary.Symbol;
      Local_Abstraction       : Dictionary.Abstractions;
      Constraint              : STree.SyntaxNode;
      DAG_Root, Stmt_Cell     : Cells.Cell;
      Stmt_Label              : Labels.Label;
      Function_Defs           : CStacks.Stack;
      Conjoined_Function_Defs : Cells.Cell;

      --------------------------------------------

      -- Constraint_Root gives the root node of the postcondition.
      -- Data_View gives the view to be used for imports and exports of the procedure.
      procedure Substitute_Parameters
        (Constraint_Root    : in out Cells.Cell;
         Data_View          : in     Dictionary.Abstractions;
         Concrete_Procedure : in     Dictionary.Symbol;
         Scope              : in     Dictionary.Scopes)
      -- replace formal parameters by actual ones in a subprogram constraint;
      --# global in     Dictionary.Dict;
      --#        in     PrefixSym;
      --#        in     SubprogramCalls;
      --#        in     SubstitutionTable;
      --#        in out LexTokenManager.State;
      --#        in out Statistics.TableUsage;
      --#        in out VCGHeap;
      --# derives Constraint_Root,
      --#         LexTokenManager.State,
      --#         Statistics.TableUsage,
      --#         VCGHeap               from *,
      --#                                    Concrete_Procedure,
      --#                                    Constraint_Root,
      --#                                    Data_View,
      --#                                    Dictionary.Dict,
      --#                                    LexTokenManager.State,
      --#                                    PrefixSym,
      --#                                    Scope,
      --#                                    SubprogramCalls,
      --#                                    SubstitutionTable,
      --#                                    VCGHeap;
      is
         Subs, P  : Cells.Cell;
         S        : CStacks.Stack;
         VarSym   : Dictionary.Symbol;
         Tilded   : Boolean;
         Change   : Boolean;
         HypStack : CStacks.Stack;

         -- procedure, generates hypothesis that all export record
         -- fields are unchanged other than that appearing as exported actual
         -- parameter.
         -- Data_View determines the view of the imports and exports of the procedure.
         procedure Add_In_Record_Field_And_Array_Element_Preservation
           (Data_View          : in Dictionary.Abstractions;
            Concrete_Procedure : in Dictionary.Symbol;
            Scope              : in Dictionary.Scopes)
         --# global in     Dictionary.Dict;
         --#        in     PrefixSym;
         --#        in     SubprogramCalls;
         --#        in     SubstitutionTable;
         --#        in out HypStack;
         --#        in out LexTokenManager.State;
         --#        in out Statistics.TableUsage;
         --#        in out VCGHeap;
         --# derives HypStack,
         --#         LexTokenManager.State,
         --#         Statistics.TableUsage,
         --#         VCGHeap               from *,
         --#                                    Concrete_Procedure,
         --#                                    Data_View,
         --#                                    Dictionary.Dict,
         --#                                    HypStack,
         --#                                    LexTokenManager.State,
         --#                                    Scope,
         --#                                    SubprogramCalls,
         --#                                    SubstitutionTable,
         --#                                    VCGHeap &
         --#         null                  from PrefixSym;
         is
            It                   : Dictionary.Iterator;
            ExportSym, UnusedSym : Dictionary.Symbol;
            Temp_Cell            : Cells.Cell;
            OpCell               : Cells.Cell;
            Converted_Export_DAG : Cells.Cell;
            Export_DAG           : Cells.Cell;
            Ptr_To_Export_DAG    : Cells.Cell;
            Ptr                  : Cells.Cell;
            EntireExport         : Cells.Cell;
            UpdateCell           : Cells.Cell;
            S                    : CStacks.Stack;

            procedure Convert_Export_DAG
              (Export_DAG           : in     Cells.Cell;
               Converted_Export_DAG :    out Cells.Cell;
               Entire_Export        :    out Cells.Cell)
            --# global in     SubprogramCalls;
            --#        in out LexTokenManager.State;
            --#        in out Statistics.TableUsage;
            --#        in out VCGHeap;
            --# derives Converted_Export_DAG,
            --#         Entire_Export         from Export_DAG,
            --#                                    VCGHeap &
            --#         LexTokenManager.State from *,
            --#                                    SubprogramCalls &
            --#         Statistics.TableUsage from *,
            --#                                    Export_DAG,
            --#                                    VCGHeap &
            --#         VCGHeap               from *,
            --#                                    Export_DAG,
            --#                                    LexTokenManager.State,
            --#                                    SubprogramCalls;
            is
               Count_Str : LexTokenManager.Lex_String;
            begin
               Structures.CopyStructure (VCGHeap, Export_DAG, Converted_Export_DAG);
               Entire_Export := Converted_Export_DAG;
               while IsSelector (Entire_Export) loop
                  Entire_Export := ArgumentOfSelector (Entire_Export);
               end loop;
               -- Entire_Export now points at entire variable cell
               Cells.Set_Kind (VCGHeap, Entire_Export, Cell_Storage.Procedure_Export);
               LexTokenManager.Insert_Nat (N       => SubprogramCalls,
                                           Lex_Str => Count_Str);
               Cells.Set_Lex_Str (VCGHeap, Entire_Export, Count_Str);
            end Convert_Export_DAG;

            -------------------

            procedure AddInSiblingHypotheses (Export_DAG, Converted_Export_DAG : in Cells.Cell;
                                              Scope                            : in Dictionary.Scopes)
            --# global in     Dictionary.Dict;
            --#        in out HypStack;
            --#        in out Statistics.TableUsage;
            --#        in out VCGHeap;
            --# derives HypStack,
            --#         Statistics.TableUsage,
            --#         VCGHeap               from *,
            --#                                    Converted_Export_DAG,
            --#                                    Dictionary.Dict,
            --#                                    Export_DAG,
            --#                                    HypStack,
            --#                                    Scope,
            --#                                    VCGHeap;
            is
               Export_DAG_Local, Converted_Export_DAG_Local : Cells.Cell;

               procedure DoOneLevelOfSiblings (Export_DAG, Converted_Export_DAG : in Cells.Cell;
                                               Scope                            : in Dictionary.Scopes)
               --# global in     Dictionary.Dict;
               --#        in out HypStack;
               --#        in out Statistics.TableUsage;
               --#        in out VCGHeap;
               --# derives HypStack,
               --#         Statistics.TableUsage,
               --#         VCGHeap               from *,
               --#                                    Converted_Export_DAG,
               --#                                    Dictionary.Dict,
               --#                                    Export_DAG,
               --#                                    HypStack,
               --#                                    Scope,
               --#                                    VCGHeap;
               is
                  It                        : Dictionary.Iterator;
                  Sym, SymOfExportedField   : Dictionary.Symbol;
                  AndCell                   : Cells.Cell;
                  OpCell                    : Cells.Cell;
                  Temp_Cell                 : Cells.Cell;
                  Export_DAG_Copy           : Cells.Cell;
                  Local_Export_DAG          : Cells.Cell;
                  Converted_Export_DAG_Copy : Cells.Cell;
                  CurrentRecord             : Dictionary.Symbol;
               begin -- DoOneLevelOfSiblings
                  CurrentRecord := Dictionary.GetType (Cells.Get_Symbol_Value (VCGHeap, RightPtr (VCGHeap, Export_DAG)));
                  -- In the array of record case, once we have passed the indexing expression, we
                  -- no longer have symbols for the record fields.  This is indicated at this point
                  -- by CurrentRecord being a NullSymbol.  In that case we can't produce any useful
                  -- hypotheses and we skip the whole remaining body
                  if not Dictionary.Is_Null_Symbol (CurrentRecord) then
                     -- suppress unchnaged field hypotheses for record fields that are
                     -- private here
                     if not Dictionary.IsPrivateType (CurrentRecord, Scope) then
                        -- or else IsPredefinedTimeType not needed here as
                        -- definitely a record -- CFR 1743
                        -- the symbol of the field being exported can be found at the top
                        -- of the export DAG
                        SymOfExportedField := Cells.Get_Symbol_Value (VCGHeap, Export_DAG);
                        -- make local copy of Export_DAG and convert its rightmostr cell to a RefCell
                        Structures.CopyStructure (VCGHeap, Export_DAG, Local_Export_DAG);
                        Temp_Cell := Local_Export_DAG;
                        while IsSelector (Temp_Cell) loop
                           Temp_Cell := ArgumentOfSelector (Temp_Cell);
                        end loop;
                        -- Temp_Cell now points at entire variable cell
                        Cells.Set_Kind (VCGHeap, Temp_Cell, Cell_Storage.Reference);

                        -- iterate through all sibling field of that being exported, type
                        -- of siblings is found one cell down from top of export dag
                        It := Dictionary.FirstRecordComponent (CurrentRecord);
                        while not Dictionary.IsNullIterator (It) loop
                           Sym := Dictionary.CurrentSymbol (It);
                           if not Dictionary.Record_Components_Are_Equal
                             (Left_Symbol  => Sym,
                              Right_Symbol => SymOfExportedField) then
                              -- need to build an "unchanged" hypothesis for this case
                              Structures.CopyStructure (VCGHeap, Local_Export_DAG, Export_DAG_Copy);
                              Structures.CopyStructure (VCGHeap, Converted_Export_DAG, Converted_Export_DAG_Copy);
                              -- substitute current field into top of each DAG
                              Cells.Set_Symbol_Value (VCGHeap, Export_DAG_Copy, Sym);
                              Cells.Set_Lex_Str (VCGHeap, Export_DAG_Copy, Dictionary.GetSimpleName (Sym));
                              Cells.Set_Symbol_Value (VCGHeap, Converted_Export_DAG_Copy, Sym);
                              Cells.Set_Lex_Str (VCGHeap, Converted_Export_DAG_Copy, Dictionary.GetSimpleName (Sym));
                              -- create an equals operator to asert them equal
                              CreateOpCell (OpCell, VCGHeap, SP_Symbols.equals);
                              -- assert equality
                              SetRightArgument (OpCell, Export_DAG_Copy, VCGHeap);
                              SetLeftArgument (OpCell, Converted_Export_DAG_Copy, VCGHeap);

                              --  CFR 1744: The HypStack may only contain a null
                              --  cell if this is the first term of the hypothesis.
                              if Cells.Is_Null_Cell (CStacks.Top (VCGHeap, HypStack)) then
                                 -- Start of a new hypothesis
                                 CStacks.Push (VCGHeap, OpCell, HypStack);
                              else
                                 -- Not the start of the hypothesis:
                                 -- 'and' result on to hypothesis stack
                                 CStacks.PopOff (VCGHeap, HypStack, AndCell);
                                 Cells.Utility.Conjoin (VCGHeap, OpCell, AndCell);
                                 CStacks.Push (VCGHeap, AndCell, HypStack);
                              end if;
                           end if;

                           It := Dictionary.NextSymbol (It);
                        end loop;
                     end if;
                  end if;
               end DoOneLevelOfSiblings;

            begin -- AddInSiblingHypotheses
               Export_DAG_Local           := Export_DAG;
               Converted_Export_DAG_Local := Converted_Export_DAG;
               while IsSelector (Export_DAG_Local) loop
                  if Cells.Get_Kind (VCGHeap, Export_DAG_Local) = Cell_Storage.Field_Access_Function then
                     DoOneLevelOfSiblings (Export_DAG_Local, Converted_Export_DAG_Local, Scope);
                  end if;
                  Export_DAG_Local           := ArgumentOfSelector (Export_DAG_Local);
                  Converted_Export_DAG_Local := ArgumentOfSelector (Converted_Export_DAG_Local);
               end loop;
            end AddInSiblingHypotheses;

         begin -- Add_In_Record_Field_And_Array_Element_Preservation
            CStacks.CreateStack (S);
            It := Dictionary.FirstExport (Data_View, Concrete_Procedure);
            while not Dictionary.IsNullIterator (It) loop
               ExportSym := Dictionary.CurrentSymbol (It);
               --# accept F, 10, UnusedSym, "UnusedSym unused here";
               Get_Export_Details
                 (Formal_Or_Global_Sym => ExportSym,
                  Concrete_Procedure   => Concrete_Procedure,
                  Entire_Actual_Sym    => UnusedSym,
                  Actual_DAG           => Ptr_To_Export_DAG);
               --# end accept;

               if IsSelector (Ptr_To_Export_DAG) then
                  -- a record field is exported so extra hypothesis is needed
                  Structures.CopyStructure (VCGHeap, Ptr_To_Export_DAG, Export_DAG);
                  Convert_Export_DAG (Ptr_To_Export_DAG,
                                      -- to get
                                      Converted_Export_DAG, EntireExport);

                  -- create hypotheses that each sibling of exported field is
                  -- unchanged
                  AddInSiblingHypotheses (Export_DAG, Converted_Export_DAG, Scope);

                  -- now continue to produce "catch-all" hypothesis that all
                  -- unchanged record fields (not just sibling fields) are
                  -- unchanged.

                  -- we need to find bottom right of export DAG and convert cell
                  -- there to a RefCell so that it is preserved as initial value
                  Temp_Cell := Export_DAG;
                  while IsSelector (Temp_Cell) loop
                     Temp_Cell := ArgumentOfSelector (Temp_Cell);
                  end loop;
                  -- Temp_Cell now points at entire variable cell
                  Cells.Set_Kind (VCGHeap, Temp_Cell, Cell_Storage.Reference);

                  -- using ingredients Export_DAG, Converted_Export_DAG and EntireExport
                  -- we can now build the hypothesis described in S.P0468.53.27
                  CStacks.Push (VCGHeap, Converted_Export_DAG, S);

                  Ptr := Export_DAG;
                  loop
                     -- Need decision here on record or array handling.
                     -- We know we are looping over either FldFunctions or ElementFunctions
                     if Cells.Get_Kind (VCGHeap, Ptr) = Cell_Storage.Field_Access_Function then
                        -- handling record field
                        -- create upf_ function cell
                        CreateUpfCell
                          (UpdateCell,
                           VCGHeap,
                           Cells.Get_Symbol_Value (VCGHeap, Ptr),
                           Cells.Get_Lex_Str (VCGHeap, Ptr));
                     else
                        -- handling an array element
                        -- create update function cell
                        CreateCellKind (UpdateCell, VCGHeap, Cell_Storage.Update_Function);
                     end if;

                     -- create comma cell
                     CreateOpCell (OpCell, VCGHeap, SP_Symbols.comma);
                     -- and link it to arguments
                     SetRightArgument (OpCell, CStacks.Top (VCGHeap, S), VCGHeap);
                     SetLeftArgument (OpCell, RightPtr (VCGHeap, Ptr), VCGHeap);

                     -- now link update cell to arguments
                     SetRightArgument (UpdateCell, OpCell, VCGHeap);

                     -- remove old expression from stack and replace by new one
                     CStacks.Pop (VCGHeap, S);
                     CStacks.Push (VCGHeap, UpdateCell, S);

                     -- move down unconverted export_DAG
                     Ptr := ArgumentOfSelector (Ptr);

                     exit when not IsSelector (Ptr);
                  end loop;

                  -- TOS is the RHS of the desired hypothesis, we must set it equal
                  -- to converted entire export
                  CreateOpCell (OpCell, VCGHeap, SP_Symbols.equals);
                  SetRightArgument (OpCell, CStacks.Top (VCGHeap, S), VCGHeap);
                  SetLeftArgument (OpCell, EntireExport, VCGHeap);
                  -- remove old expression from stack and replace by new one
                  CStacks.Pop (VCGHeap, S);
                  CStacks.Push (VCGHeap, OpCell, S);

                  -- TOS is the desired new hypothesis, needs anding into current one
                  CStacks.PopOff (VCGHeap, HypStack, OpCell);
                  Cells.Utility.Conjoin (VCGHeap, CStacks.Top (VCGHeap, S), OpCell);
                  CStacks.Push (VCGHeap, OpCell, HypStack);

                  -- clean up local stack
                  CStacks.Pop (VCGHeap, S);

               end if;
               It := Dictionary.NextSymbol (It);
            end loop;
            --# accept F, 35, PrefixSym, "Coupled to UnusedSym only" &
            --#        F, 33, UnusedSym, "UnusedSym unused here";
         end Add_In_Record_Field_And_Array_Element_Preservation;

         -----------------

         procedure Substitute_Tilded_Parameter (The_Cell           : in Cells.Cell;
                                                Concrete_Procedure : in Dictionary.Symbol)
         --# global in     Dictionary.Dict;
         --#        in     PrefixSym;
         --#        in     SubstitutionTable;
         --#        in out VCGHeap;
         --# derives VCGHeap from *,
         --#                      Concrete_Procedure,
         --#                      Dictionary.Dict,
         --#                      PrefixSym,
         --#                      SubstitutionTable,
         --#                      The_Cell;
         is
            Export_DAG : Cells.Cell;
            ExportSym  : Dictionary.Symbol;
         begin
            Get_Export_Details
              (Formal_Or_Global_Sym => Cells.Get_Symbol_Value (VCGHeap, The_Cell),
               Concrete_Procedure   => Concrete_Procedure,
               Entire_Actual_Sym    => ExportSym,
               Actual_DAG           => Export_DAG);
            -- see if the DAG represents a field access or array element
            if not Cells.Is_Null_Cell (Export_DAG)
              and then (Cells.Get_Kind (VCGHeap, Export_DAG) = Cell_Storage.Field_Access_Function
                          or else Cells.Get_Kind (VCGHeap, Export_DAG) = Cell_Storage.Element_Function) then
               -- there is a field access, substitute DAG for cell contents
               Cells.Copy_Contents (VCGHeap, Export_DAG, The_Cell);
            else -- no field access, just substitute symbol of actual
               Cells.Set_Symbol_Value (VCGHeap, The_Cell, ExportSym);
            end if;
         end Substitute_Tilded_Parameter;

      begin -- Substitute_Parameters

         -- HypStack is used to ease joining of extra hypotheses concerning
         -- exportation of record fields to the main hypothesis where the called
         -- procedure's post-condition is assumed.

         CStacks.CreateStack (HypStack);
         CStacks.Push (VCGHeap, Constraint_Root, HypStack);

         -- stack S is used for the
         -- DAG traversal algorithm of D.E. Knuth, Fundamental Algorithms, p.317;
         CStacks.CreateStack (S);
         P := Constraint_Root;
         loop
            loop
               exit when Cells.Is_Null_Cell (P);
               CStacks.Push (VCGHeap, P, S);
               if Is_Leaf (Node     => P,
                           VCG_Heap => VCGHeap) then
                  P := Cells.Null_Cell;
               else
                  P := LeftPtr (VCGHeap, P);
               end if;
            end loop;
            exit when CStacks.IsEmpty (S);
            P := CStacks.Top (VCGHeap, S);
            CStacks.Pop (VCGHeap, S);
            if Is_Leaf (Node     => P,
                        VCG_Heap => VCGHeap) then
               if Cells.Get_Kind (VCGHeap, P) = Cell_Storage.Reference
                 or else Cells.Get_Kind (VCGHeap, P) = Cell_Storage.Unconstrained_Attribute_Prefix then

                  VarSym := Cells.Get_Symbol_Value (VCGHeap, P);

                  Tilded := Cells.Get_Op_Symbol (VCGHeap, P) = SP_Symbols.tilde;

                  if Dictionary.IsExport (Data_View, Concrete_Procedure, VarSym) then

                     if Cells.Get_Kind (VCGHeap, P) = Cell_Storage.Unconstrained_Attribute_Prefix then
                        -- Although VarSym is an export, it is used here as an attribute prefix
                        -- and we don't want to convert it to an export cell or do anything to
                        -- the tilde, rather we want to replace the variable name with a
                        -- constraining type mark
                        Substitute_Import_Constraint
                          (Sym                => VarSym,
                           Concrete_Procedure => Concrete_Procedure,
                           Change             => Change,
                           Result             => Subs);
                        if Change then
                           Cells.Copy_Contents (VCGHeap, Subs, P);
                        end if;
                     else
                        -- not an unconstrained attribute prefix - handle as before
                        if Tilded then
                           if Dictionary.Is_Global_Variable (Data_View, Concrete_Procedure, VarSym) then
                              Cells.Set_Op_Symbol (VCGHeap, P, SP_Symbols.RWnull);
                           else   -- must be a parameter
                              Cells.Set_Op_Symbol (VCGHeap, P, SP_Symbols.RWnull);
                              Substitute_Tilded_Parameter (The_Cell           => P,
                                                           Concrete_Procedure => Concrete_Procedure);
                           end if;
                        else -- not Tilded, but still an export
                           Convert_Cell_To_Export_Cell (Cell_Name          => P,
                                                        Concrete_Procedure => Concrete_Procedure);
                        end if;
                     end if;
                  else -- process imports

                     --  In a post-condition, a reference to an
                     --  attribute of an unconstrained array parameter
                     --  appears as am imported
                     --  SubprogramParameterConstraint here here, so
                     if Dictionary.IsSubprogramParameter (VarSym) or Dictionary.IsParameterConstraint (VarSym) then

                        if Cells.Get_Kind (VCGHeap, P) = Cell_Storage.Reference then
                           Substitute_Import
                             (Sym                => VarSym,
                              Concrete_Procedure => Concrete_Procedure,
                              Change             => Change,
                              Result             => Subs);
                           if Change then
                              Cells.Copy_Contents (VCGHeap, Subs, P);
                           end if;
                        elsif Cells.Get_Kind (VCGHeap, P) = Cell_Storage.Unconstrained_Attribute_Prefix then
                           Substitute_Import_Constraint
                             (Sym                => VarSym,
                              Concrete_Procedure => Concrete_Procedure,
                              Change             => Change,
                              Result             => Subs);
                           if Change then
                              Cells.Copy_Contents (VCGHeap, Subs, P);
                           end if;
                        end if;
                     end if;
                  end if;
               end if;
               P := Cells.Null_Cell;
            else
               P := RightPtr (VCGHeap, P);
            end if;
         end loop;

         -- where record fields or array elements are exported we need to create a hypothis
         -- in terms of the entire export and, for records, assert that all
         -- unaffected fields are unchanged.
         Add_In_Record_Field_And_Array_Element_Preservation
           (Data_View          => Data_View,
            Concrete_Procedure => Concrete_Procedure,
            Scope              => Scope);

         --# accept F, 10, HypStack, "HypStack unused here";
         CStacks.PopOff (VCGHeap, HypStack, Constraint_Root);
         --# end accept;

      end Substitute_Parameters;

      -- Data_View gives the view of the imports and exports of the procedure to be used.
      procedure Assume_Type_Of_Actual_Exports
        (DAG_Root           : in out Cells.Cell;
         Data_View          : in     Dictionary.Abstractions;
         Concrete_Procedure : in     Dictionary.Symbol;
         Scope              : in     Dictionary.Scopes)
      --# global in     CommandLineData.Content;
      --#        in out ContainsReals;
      --#        in out Dictionary.Dict;
      --#        in out LexTokenManager.State;
      --#        in out SPARK_IO.File_Sys;
      --#        in out Statistics.TableUsage;
      --#        in out VCGFailure;
      --#        in out VCGHeap;
      --# derives ContainsReals,
      --#         DAG_Root,
      --#         Dictionary.Dict,
      --#         LexTokenManager.State,
      --#         SPARK_IO.File_Sys,
      --#         Statistics.TableUsage,
      --#         VCGFailure,
      --#         VCGHeap               from *,
      --#                                    CommandLineData.Content,
      --#                                    Concrete_Procedure,
      --#                                    DAG_Root,
      --#                                    Data_View,
      --#                                    Dictionary.Dict,
      --#                                    LexTokenManager.State,
      --#                                    Scope,
      --#                                    VCGHeap;
      is
         It        : Dictionary.Iterator;
         ExportVar : Dictionary.Symbol;
         Type_Sym  : Dictionary.Symbol;
      begin
         It := Dictionary.FirstExport (Data_View, Concrete_Procedure);
         while not Dictionary.IsNullIterator (It) loop
            ExportVar := Dictionary.CurrentSymbol (It);
            if IsDirectlyVisible (ExportVar, Scope) and then not Dictionary.IsOwnVariableOrConstituentWithMode (ExportVar) then
               Type_Sym := Dictionary.GetType (ExportVar);
               if not Dictionary.IsPrivateType (Type_Sym, Scope) or else Dictionary.IsPredefinedTimeType (Type_Sym) then
                  ConjoinParamConstraint (Type_Sym, ExportVar, Scope, False, DAG_Root);
               end if;
            end if;
            It := Dictionary.NextSymbol (It);
         end loop;
      end Assume_Type_Of_Actual_Exports;

   begin -- Model_Postcondition

      if Dictionary.IsInstantiation (Concrete_Procedure) then
         -- for instantiations we go and get the constraint of the original generic
         Instantiated_Subprogram := Concrete_Procedure;
         Local_Abstraction       := Dictionary.IsAbstract;
      else -- not generic
         Instantiated_Subprogram := Dictionary.NullSymbol;
         Local_Abstraction       := Abstraction;
      end if;

      Constraint := STree.RefToNode (Dictionary.GetPostcondition (Local_Abstraction, Concrete_Procedure));
      if Constraint /= STree.NullNode then
         -- Initialize the function definition stack
         CStacks.CreateStack (Function_Defs);

         Build_Annotation_Expression
           (Exp_Node                         => Constraint,
            Instantiated_Subprogram          => Instantiated_Subprogram,
            Scope                            => Dictionary.Set_Visibility (The_Visibility => Dictionary.Local,
                                                                           The_Unit       => Concrete_Procedure),
            Calling_Scope                    => Scope,
            Force_Abstract                   => Abstraction = Dictionary.IsAbstract,
            Loop_Stack                       => LoopStack,
            Generate_Function_Instantiations => True,
            VC_Failure                       => VCGFailure,
            VC_Contains_Reals                => ContainsReals,
            VCG_Heap                         => VCGHeap,
            DAG_Root                         => DAG_Root,
            Function_Defs                    => Function_Defs);

         if not CStacks.IsEmpty (Function_Defs) then
            -- Functions are called within the procedure's post condition
            -- Conjoin all the function definitions on the stack
            --# accept F, 10, Function_Defs, "The stack has been emptied";
            Join_And (Stack    => Function_Defs,
                      Conjunct => Conjoined_Function_Defs,
                      VCG_Heap => VCGHeap);
            --# end accept;

            -- conjoin the function definitions wit the procedure's post condition
            Cells.Utility.Conjoin (VCGHeap, Conjoined_Function_Defs, DAG_Root);
         end if;
      else
         DAG_Root := Cells.Null_Cell;
      end if;

      -- Ensure the correct view of the exports is used determined by the value of Data_View
      Assume_Type_Of_Actual_Exports
        (DAG_Root           => DAG_Root,
         Data_View          => Data_View,
         Concrete_Procedure => Concrete_Procedure,
         Scope              => Scope);

      -- CFR 1744: Call Substitute_Parameters even if DAG_Root is a null cell
      -- in order to generate hypothesis for invariant fields of composite
      -- objects where an exported variable of a private type is a component
      -- of the composite object.
      -- Ensure the correct view of imports and exports is used determined by the value of Data_View
      Substitute_Parameters
        (Constraint_Root    => DAG_Root,
         Data_View          => Data_View,
         Concrete_Procedure => Concrete_Procedure,
         Scope              => Scope);

      PrepareLabel (VCGHeap, Stmt_Label, Stmt_Cell);
      SetRightArgument (Stmt_Cell, DAG_Root, VCGHeap);
      Chain (Stmt_Label, VCGHeap);
   end Model_Postcondition;

   procedure CheckTypeOfActualExportParams
   --# global in     Concrete_Procedure;
   --#        in     Dictionary.Dict;
   --#        in     Scope;
   --#        in     SubstitutionTable;
   --#        in out CheckStack;
   --#        in out ContainsReals;
   --#        in out ShortCircuitStack;
   --#        in out Statistics.TableUsage;
   --#        in out VCGHeap;
   --# derives CheckStack,
   --#         ContainsReals,
   --#         ShortCircuitStack,
   --#         Statistics.TableUsage,
   --#         VCGHeap               from *,
   --#                                    CheckStack,
   --#                                    Concrete_Procedure,
   --#                                    Dictionary.Dict,
   --#                                    Scope,
   --#                                    ShortCircuitStack,
   --#                                    SubstitutionTable,
   --#                                    VCGHeap;
   is
      ParamElement    : Cells.Cell;
      ParamNum        : Natural;
      ActualParamCell : Cells.Cell;
      ActualParamSym  : Dictionary.Symbol;
      ActualParamType : Dictionary.Symbol;
      FormalParamSym  : Dictionary.Symbol;

      -- This subprogram is added merely as a temporary measure
      -- to flag up presence of additional VCs being generated
      -- as a result of the bug under SEPR 2124.
      -- To be removed in a future release of the Examiner.
      procedure SEPR2124Warning
      --# derives ;
      is
         --# hide SEPR2124Warning;
      begin
         -- Only output warning in case of different types in use
         if not Dictionary.Types_Are_Equal
           (Left_Symbol        => Dictionary.GetType (FormalParamSym),
            Right_Symbol       => ActualParamType,
            Full_Range_Subtype => False) then
            ErrorHandler.Semantic_Warning
              (Err_Num  => 420,
               Position => LexTokenManager.Token_Position'(Start_Line_No => LexTokenManager.Line_Numbers (LineNmbr),
                                                           Start_Pos     => 0),
               Id_Str   => LexTokenManager.Null_String);
         end if;
      end SEPR2124Warning;

   begin
      ParamNum     := 1;
      ParamElement := Clists.FirstCell (VCGHeap, SubstitutionTable);

      while not Cells.Is_Null_Cell (ParamElement) loop
         FormalParamSym  := Dictionary.GetSubprogramParameter (Concrete_Procedure, ParamNum);
         ActualParamCell := AuxPtr (VCGHeap, ParamElement);

         -- Subprogram parameters cannot be refined they are always abstract
         if Dictionary.IsExport (Dictionary.IsAbstract, Concrete_Procedure, FormalParamSym) then
            -- We need to work out the subtype of the actual parameter
            -- here for the case where the actual is a subtype of the
            -- formal parameter, and so requires a range check.
            if Cells.Get_Kind (VCGHeap, ActualParamCell) = Cell_Storage.Field_Access_Function then

               ActualParamSym  := Cells.Get_Symbol_Value (VCGHeap, ActualParamCell);
               ActualParamType := Dictionary.GetType (ActualParamSym);

               SEPR2124Warning;

            elsif Cells.Get_Kind (VCGHeap, ActualParamCell) = Cell_Storage.Element_Function then

               -- BuildExpnDAG.ProcessNameArgumentList will have planted
               -- the type of the array component here as the SymValue of
               -- the ActualParamCell, so
               ActualParamType := Cells.Get_Symbol_Value (VCGHeap, ActualParamCell);

               SEPR2124Warning;

            else -- not an array element or record field selector, so must be a simple variable
               ActualParamSym  := Cells.Get_Symbol_Value (VCGHeap, ActualParamCell);
               ActualParamType := Dictionary.GetType (ActualParamSym);

            end if;

            CheckConstraintRunTimeError
              (ActualParamType,
               ActualParamCell,
               Scope,
               VCGHeap,
               ShortCircuitStack,
               CheckStack,
               ContainsReals);

         end if;
         ParamElement := Clists.NextCell (VCGHeap, ParamElement);
         ParamNum     := ParamNum + 1;
      end loop;
   end CheckTypeOfActualExportParams;

   ----------------------------------------------------------------
   -- Data_View gives the view of the imports and exports to be used.
   procedure BuildVCSAssignments (Data_View : in Dictionary.Abstractions)
   --# global in     Concrete_Procedure;
   --#        in     Dictionary.Dict;
   --#        in     PrefixSym;
   --#        in     SubprogramCalls;
   --#        in     SubstitutionTable;
   --#        in out Graph.Table;
   --#        in out LexTokenManager.State;
   --#        in out Statistics.TableUsage;
   --#        in out StmtStack.S;
   --#        in out VCGHeap;
   --# derives Graph.Table,
   --#         StmtStack.S,
   --#         VCGHeap               from Concrete_Procedure,
   --#                                    Data_View,
   --#                                    Dictionary.Dict,
   --#                                    Graph.Table,
   --#                                    LexTokenManager.State,
   --#                                    PrefixSym,
   --#                                    StmtStack.S,
   --#                                    SubprogramCalls,
   --#                                    SubstitutionTable,
   --#                                    VCGHeap &
   --#         LexTokenManager.State from *,
   --#                                    Concrete_Procedure,
   --#                                    Data_View,
   --#                                    Dictionary.Dict,
   --#                                    SubprogramCalls &
   --#         Statistics.TableUsage from *,
   --#                                    Concrete_Procedure,
   --#                                    Data_View,
   --#                                    Dictionary.Dict,
   --#                                    LexTokenManager.State,
   --#                                    PrefixSym,
   --#                                    SubprogramCalls,
   --#                                    SubstitutionTable,
   --#                                    VCGHeap;

   is
      It                       : Dictionary.Iterator;
      ExportSym                : Dictionary.Symbol;
      ExportCell, AssignedCell : Cells.Cell;
      ExportsFound             : Boolean;
      ModList                  : Cells.Cell;
      StmtPair                 : Cells.Cell;
      Stmt_Label               : Labels.Label;
      EntireExportSym          : Dictionary.Symbol;
      Unused_Export_DAG        : Cells.Cell;

   begin
      ExportsFound := False;
      Clists.CreateList (VCGHeap, ModList);
      It := Dictionary.FirstExport (Data_View, Concrete_Procedure);

      while not Dictionary.IsNullIterator (It) loop
         ExportSym := Dictionary.CurrentSymbol (It);
         if not Dictionary.Is_Null_Variable (ExportSym) then --don't model data sinks
            ExportsFound := True;
            --# accept F, 10, Unused_Export_DAG, "Unused_Export_DAG unused here";
            Get_Export_Details
              (Formal_Or_Global_Sym => ExportSym,
               Concrete_Procedure   => Concrete_Procedure,
               Entire_Actual_Sym    => EntireExportSym,
               Actual_DAG           => Unused_Export_DAG);
            --# end accept;
            CreateModifiedCell (ExportCell, VCGHeap, EntireExportSym);
            Clists.InsertCell (VCGHeap, ExportCell, ModList);
            Cells.Create_Cell (VCGHeap, AssignedCell);
            Cells.Set_Symbol_Value (VCGHeap, AssignedCell, EntireExportSym);
            Convert_Cell_To_Export_Cell (Cell_Name          => AssignedCell,
                                         Concrete_Procedure => Concrete_Procedure);
            SetRightArgument (ExportCell, AssignedCell, VCGHeap);
         end if;
         It := Dictionary.NextSymbol (It);
      end loop;

      if ExportsFound then
         PrepareLabel (VCGHeap, Stmt_Label, StmtPair);
         SetAuxPtr (StmtPair, ModList, VCGHeap);
      else
         CreateUnitLabel (Stmt_Label, VCGHeap);
      end if;
      Chain (Stmt_Label, VCGHeap);
      --# accept F, 33, Unused_Export_DAG, "Unused_Export_DAG unused here";
   end BuildVCSAssignments;

begin -- ModelProcedureCall
   SubprogramCalls := SubprogramCalls + 1;
   -- Node represents procedure_call_statement;

   -- If we are calling an inherited root operation then the proc_call node will
   -- have been seeded with the actual procedure that got called.
   Concrete_Procedure := STree.NodeSymbol (Node);
   if not Dictionary.Is_Null_Symbol (Concrete_Procedure) and then Dictionary.Is_Variable (Concrete_Procedure) then
      -- We have found something in the syntax tree but it is not a subprogram.  In that
      -- case it must be a protected object prefix to a protected op call.  We need this so
      -- we can subtitute instances of PT in annotations with PO.  PO is what we have just found.
      PrefixSym          := Concrete_Procedure;
      Concrete_Procedure := Dictionary.NullSymbol;
   end if;

   if Dictionary.Is_Null_Symbol (Concrete_Procedure) then
      -- no root proc symbol found so carry on and find a procedure name locally

      BuildExpnDAG
        (STree.Child_Node (Current_Node => STree.Child_Node (Current_Node => Node)),
         LScope,
         Scope,
         LineNmbr,
         True, --PNA observation, 8/3/4, why is RTC turned on when all we are doing is identifying proc name?
         False,
         LoopStack,
         FlowHeap,
         VCGHeap,
         ContainsReals,
         VCGFailure,
         ShortCircuitStack,
         CheckStack,
         KindOfStackedCheck,
         -- to get
         Procedure_Name_Cell);

      Concrete_Procedure := Cells.Get_Symbol_Value (VCGHeap, Procedure_Name_Cell);
   end if;

   -- First obtain what the view of the pre and post conditions is -
   -- abstract or refined?
   Abstraction := Dictionary.GetConstraintAbstraction (Concrete_Procedure, LScope);

   if Abstraction = Dictionary.IsRefined then
      -- The view of the pre and post condition is refined.
      -- Determine whether the view of the data should be
      -- Abstract (Proof Refinement only) or
      -- Refined  (Data Refinement is present).
      if Dictionary.IsNullIterator (Dictionary.FirstGlobalVariable (Dictionary.IsRefined, Concrete_Procedure)) then
         -- No Data Refinement.
         Data_View := Dictionary.IsAbstract;
      else
         -- Data Refinement is present.
         Data_View := Dictionary.IsRefined;
      end if;
   else
      -- Only proof refinement is present.
      Data_View := Dictionary.IsAbstract;
   end if;

   Build_Substitution_Table (Node               => Node,
                             Concrete_Procedure => Concrete_Procedure);

   Model_Precondition (Abstraction        => Abstraction,
                       Concrete_Procedure => Concrete_Procedure);

   UnStackRtcs (LineNmbr, VCGHeap, CheckStack, KindOfStackedCheck);
   Model_Postcondition
     (Abstraction        => Abstraction,
      Data_View          => Data_View,
      Concrete_Procedure => Concrete_Procedure,
      Scope              => Scope);

   BuildVCSAssignments (Data_View => Data_View);

   CheckTypeOfActualExportParams;
   UnStackRtcs (LineNmbr, VCGHeap, CheckStack, KindOfStackedCheck);

   Clists.DisposeOfList (VCGHeap, SubstitutionTable);
end ModelProcedureCall;
