-------------------------------------------------------------------------------
-- (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.
--
--=============================================================================

-- Wffs:
-- 1. There must be one actual for each formal.
-- 2. Each actual must be of the right type and kind (i.e. object or type).
--
-- Actions:
-- Wellformed formal/actual associations are written to the Dictionary
-- and associated with the Instantiation_Sym.

separate (Sem.Wf_Generic_Subprogram_Instantiation)
procedure Wf_Generic_Actual_Part
  (Actual_Part_Node  : in     STree.SyntaxNode;
   Instantiation_Sym : in     Dictionary.Symbol;
   Scope             : in     Dictionary.Scopes;
   Component_Data    : in out ComponentManager.ComponentData;
   The_Heap          : in out Heap.HeapRecord;
   Error_Found       :    out Boolean)
is
   Current_Node : STree.SyntaxNode;

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

   procedure Process_Generic_Type_Parameter
     (Formal_Sym        : in     Dictionary.Symbol;
      Expression_Node   : in     STree.SyntaxNode;
      Instantiation_Sym : in     Dictionary.Symbol;
      Scope             : in     Dictionary.Scopes;
      Error_Found       : in out Boolean;
      Component_Data    : in out ComponentManager.ComponentData;
      The_Heap          : in out Heap.HeapRecord)
   --# global in     CommandLineData.Content;
   --#        in     ContextManager.Ops.File_Heap;
   --#        in     ContextManager.Ops.Unit_Heap;
   --#        in     ContextManager.Ops.Unit_Stack;
   --#        in out Aggregate_Stack.State;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out LexTokenManager.State;
   --#        in out SLI.State;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --#        in out STree.Table;
   --# derives Aggregate_Stack.State,
   --#         Component_Data,
   --#         LexTokenManager.State,
   --#         Statistics.TableUsage,
   --#         STree.Table,
   --#         The_Heap                   from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         Expression_Node,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         The_Heap &
   --#         Dictionary.Dict,
   --#         Error_Found                from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         Error_Found,
   --#                                         Expression_Node,
   --#                                         Formal_Sym,
   --#                                         Instantiation_Sym,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         The_Heap &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.File_Heap,
   --#                                         ContextManager.Ops.Unit_Heap,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         Expression_Node,
   --#                                         Formal_Sym,
   --#                                         Instantiation_Sym,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         SLI.State,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         The_Heap &
   --#         SLI.State                  from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.File_Heap,
   --#                                         ContextManager.Ops.Unit_Heap,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         Expression_Node,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         The_Heap;
   --# pre Syntax_Node_Type (Expression_Node, STree.Table) = SP_Symbols.expression;
   --# post STree.Table = STree.Table~;
   is
      Expression_Result        : Exp_Record;
      Is_A_Name                : Boolean;
      Unused_Ref_Vars          : SeqAlgebra.Seq;
      Actual_Type, Formal_Type : Dictionary.Symbol;

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

      procedure Check_Array_Type_Compatibility
        (Actual_Type, Formal_Type : in     Dictionary.Symbol;
         Instantiation_Sym        : in     Dictionary.Symbol;
         Scope                    : in     Dictionary.Scopes;
         Position                 : in     LexTokenManager.Token_Position;
         Error_Found              : in out Boolean)
      --# global in     CommandLineData.Content;
      --#        in     Dictionary.Dict;
      --#        in     LexTokenManager.State;
      --#        in out ErrorHandler.Error_Context;
      --#        in out SPARK_IO.File_Sys;
      --# derives ErrorHandler.Error_Context,
      --#         SPARK_IO.File_Sys          from Actual_Type,
      --#                                         CommandLineData.Content,
      --#                                         Dictionary.Dict,
      --#                                         ErrorHandler.Error_Context,
      --#                                         Formal_Type,
      --#                                         Instantiation_Sym,
      --#                                         LexTokenManager.State,
      --#                                         Position,
      --#                                         Scope,
      --#                                         SPARK_IO.File_Sys &
      --#         Error_Found                from *,
      --#                                         Actual_Type,
      --#                                         Dictionary.Dict,
      --#                                         Formal_Type,
      --#                                         Instantiation_Sym,
      --#                                         Scope;
      is
         Actual_Type_Local, Formal_Type_Local       : Dictionary.Symbol;
         Actual_Type_Iterator, Formal_Type_Iterator : Dictionary.Iterator;
      begin
         -- Check the kind of array
         -- Both formal and actual must be same constrained/unconstrained
         if Dictionary.Is_Constrained_Array_Type_Mark (Actual_Type, Scope)
           and then Dictionary.Is_Unconstrained_Array_Type_Mark (Formal_Type, Scope) then
            Error_Found := True;
            ErrorHandler.Semantic_Error2
              (Err_Num   => 649,
               Reference => ErrorHandler.No_Reference,
               Position  => Position,
               Id_Str1   => Dictionary.GetSimpleName (Actual_Type),
               Id_Str2   => Dictionary.GetSimpleName (Formal_Type));
         end if;
         -- reverse check
         if Dictionary.Is_Unconstrained_Array_Type_Mark (Actual_Type, Scope)
           and then Dictionary.Is_Constrained_Array_Type_Mark (Formal_Type, Scope) then
            Error_Found := True;
            ErrorHandler.Semantic_Error2
              (Err_Num   => 650,
               Reference => ErrorHandler.No_Reference,
               Position  => Position,
               Id_Str1   => Dictionary.GetSimpleName (Actual_Type),
               Id_Str2   => Dictionary.GetSimpleName (Formal_Type));
         end if;

         -- Check the type of the component of the array
         Actual_Type_Local := Dictionary.GetArrayComponent (Actual_Type);
         Formal_Type_Local := Dictionary.GetArrayComponent (Formal_Type);
         if Dictionary.TypeIsGeneric (Formal_Type_Local) then
            Formal_Type_Local := Dictionary.ActualOfGenericFormalType (Formal_Type_Local, Instantiation_Sym);
            if Dictionary.Is_Null_Symbol (Formal_Type_Local) then
               ErrorHandler.Semantic_Error2
                 (Err_Num   => 645,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Position,
                  Id_Str1   => Dictionary.GetSimpleName (Actual_Type_Local),
                  Id_Str2   => Dictionary.GetSimpleName (Dictionary.GetArrayComponent (Formal_Type)));
               Error_Found := True;
            end if;
         end if;
         if not Dictionary.Is_Null_Symbol (Formal_Type_Local)
           and then not Dictionary.Types_Are_Equal
           (Left_Symbol        => Actual_Type_Local,
            Right_Symbol       => Formal_Type_Local,
            Full_Range_Subtype => True) then
            ErrorHandler.Semantic_Error2
              (Err_Num   => 645,
               Reference => ErrorHandler.No_Reference,
               Position  => Position,
               Id_Str1   => Dictionary.GetSimpleName (Actual_Type_Local),
               Id_Str2   => Dictionary.GetSimpleName (Formal_Type_Local));
            Error_Found := True;
         end if;

         -- Check the type of the index of the array
         Actual_Type_Iterator := Dictionary.FirstArrayIndex (Actual_Type);
         Formal_Type_Iterator := Dictionary.FirstArrayIndex (Formal_Type);
         loop
            exit when Actual_Type_Iterator = Dictionary.NullIterator and then Formal_Type_Iterator = Dictionary.NullIterator;
            if Actual_Type_Iterator = Dictionary.NullIterator then
               ErrorHandler.Semantic_Error2
                 (Err_Num   => 647,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Position,
                  Id_Str1   => Dictionary.GetSimpleName (Actual_Type),
                  Id_Str2   => Dictionary.GetSimpleName (Formal_Type));
               Error_Found := True;
               exit;
            end if;
            if Formal_Type_Iterator = Dictionary.NullIterator then
               ErrorHandler.Semantic_Error2
                 (Err_Num   => 648,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Position,
                  Id_Str1   => Dictionary.GetSimpleName (Actual_Type),
                  Id_Str2   => Dictionary.GetSimpleName (Formal_Type));
               Error_Found := True;
               exit;
            end if;
            Actual_Type_Local := Dictionary.CurrentSymbol (Actual_Type_Iterator);
            Formal_Type_Local := Dictionary.CurrentSymbol (Formal_Type_Iterator);
            if Dictionary.TypeIsGeneric (Formal_Type_Local) then
               Formal_Type_Local := Dictionary.ActualOfGenericFormalType (Formal_Type_Local, Instantiation_Sym);
               if Dictionary.Is_Null_Symbol (Formal_Type_Local) then
                  ErrorHandler.Semantic_Error2
                    (Err_Num   => 646,
                     Reference => ErrorHandler.No_Reference,
                     Position  => Position,
                     Id_Str1   => Dictionary.GetSimpleName (Actual_Type_Local),
                     Id_Str2   => Dictionary.GetSimpleName (Dictionary.CurrentSymbol (Formal_Type_Iterator)));
                  Error_Found := True;
               end if;
            end if;
            if not Dictionary.Is_Null_Symbol (Formal_Type_Local)
              and then not Dictionary.Types_Are_Equal
              (Left_Symbol        => Actual_Type_Local,
               Right_Symbol       => Formal_Type_Local,
               Full_Range_Subtype => True) then
               ErrorHandler.Semantic_Error2
                 (Err_Num   => 646,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Position,
                  Id_Str1   => Dictionary.GetSimpleName (Actual_Type_Local),
                  Id_Str2   => Dictionary.GetSimpleName (Formal_Type_Local));
               Error_Found := True;
            end if;
            Actual_Type_Iterator := Dictionary.NextSymbol (Actual_Type_Iterator);
            Formal_Type_Iterator := Dictionary.NextSymbol (Formal_Type_Iterator);
         end loop;
      end Check_Array_Type_Compatibility;

   begin -- Process_Generic_Type_Parameter

      -- The actual parameter takes the form of an expression but must actually be a typemark.
      -- We can use WalkName to recover the symbol, then check that it is a type and that it
      -- compatible with generic type.  Matching pairs are added to the dictionary and associated
      -- with the symbol of the instantiated unit.
      SeqAlgebra.CreateSeq (The_Heap, Unused_Ref_Vars);
      Walk_Name
        (Exp_Node       => Expression_Node,
         Scope          => Scope,
         Component_Data => Component_Data,
         The_Heap       => The_Heap,
         Result         => Expression_Result,
         Is_A_Name      => Is_A_Name,
         Ref_Var_Param  => Unused_Ref_Vars);
      SeqAlgebra.DisposeOfSeq (The_Heap, Unused_Ref_Vars);
      if not Is_A_Name or else Expression_Result.Sort /= Is_Type_Mark then
         -- we have a general expression which cannot possibly be a type mark or
         --  we have a name but it's not a type mark
         ErrorHandler.Semantic_Error
           (Err_Num   => 95,
            Reference => ErrorHandler.No_Reference,
            Position  => Node_Position (Node => Expression_Node),
            Id_Str    => LexTokenManager.Null_String);
         Error_Found := True;
      else
         -- we have a type mark
         Actual_Type := Expression_Result.Type_Symbol;
         Formal_Type := Dictionary.GetType (Formal_Sym);
         if Dictionary.IsArrayTypeMark (TheSymbol => Formal_Type,
                                        Scope     => Scope)
           and then Dictionary.IsArrayTypeMark (TheSymbol => Actual_Type,
                                                Scope     => Scope) then
            Check_Array_Type_Compatibility
              (Actual_Type       => Actual_Type,
               Formal_Type       => Formal_Type,
               Instantiation_Sym => Instantiation_Sym,
               Scope             => Scope,
               Position          => Node_Position (Node => Expression_Node),
               Error_Found       => Error_Found);
            if Error_Found then
               Actual_Type := Dictionary.GetUnknownTypeMark;
            end if;
         else
            if not Dictionary.IsValidGenericTypeAssociation (Formal => Formal_Type,
                                                             Actual => Actual_Type,
                                                             Scope  => Scope) then
               ErrorHandler.Semantic_Error2
                 (Err_Num   => 636,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Node_Position (Node => Expression_Node),
                  Id_Str1   => Dictionary.GetSimpleName (Actual_Type),
                  Id_Str2   => Dictionary.GetSimpleName (Formal_Type));
               Error_Found := True;
               Actual_Type := Dictionary.GetUnknownTypeMark;
            end if;
         end if;

         -- above call will change Actual_Type to the UnknownType if there is an error
         Dictionary.AddGenericTypeAssociation
           (SubprogramOrPackage => Instantiation_Sym,
            Comp_Unit           => ContextManager.Ops.Current_Unit,
            Declaration         => Dictionary.Location'(Start_Position => Node_Position (Node => Expression_Node),
                                                        End_Position   => Node_Position (Node => Expression_Node)),
            FormalSym           => Formal_Type,
            ActualSym           => Actual_Type);
      end if;
   end Process_Generic_Type_Parameter;

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

   procedure Process_Generic_Object_Parameter
     (Formal_Sym        : in     Dictionary.Symbol;
      Expression_Node   : in     STree.SyntaxNode;
      Instantiation_Sym : in     Dictionary.Symbol;
      Scope             : in     Dictionary.Scopes;
      Error_Found       : in out Boolean;
      The_Heap          : in out Heap.HeapRecord)
   --# global in     CommandLineData.Content;
   --#        in     ContextManager.Ops.File_Heap;
   --#        in     ContextManager.Ops.Unit_Heap;
   --#        in     ContextManager.Ops.Unit_Stack;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out LexTokenManager.State;
   --#        in out SLI.State;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --#        in out STree.Table;
   --#           out Aggregate_Stack.State;
   --# derives Aggregate_Stack.State,
   --#         Dictionary.Dict,
   --#         LexTokenManager.State,
   --#         STree.Table,
   --#         The_Heap                   from CommandLineData.Content,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         Expression_Node,
   --#                                         Formal_Sym,
   --#                                         Instantiation_Sym,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         The_Heap &
   --#         ErrorHandler.Error_Context,
   --#         SLI.State,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         ContextManager.Ops.File_Heap,
   --#                                         ContextManager.Ops.Unit_Heap,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         Expression_Node,
   --#                                         Formal_Sym,
   --#                                         Instantiation_Sym,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         SLI.State,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         The_Heap &
   --#         Error_Found,
   --#         Statistics.TableUsage      from *,
   --#                                         CommandLineData.Content,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         Expression_Node,
   --#                                         Formal_Sym,
   --#                                         Instantiation_Sym,
   --#                                         LexTokenManager.State,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         The_Heap;
   --# pre Syntax_Node_Type (Expression_Node, STree.Table) = SP_Symbols.expression;
   --# post STree.Table = STree.Table~;
   is
      Actual_Type           : Dictionary.Symbol;
      Unused_Component_Data : ComponentManager.ComponentData;
      Unwanted_Seq          : SeqAlgebra.Seq;
      Exp_Result            : Exp_Record;
      Value, Constant_Name  : LexTokenManager.Lex_String;
      Constant_Name_String  : E_Strings.T;
      Constant_Sym          : Dictionary.Symbol := Dictionary.NullSymbol;
      Constant_Location     : Dictionary.Location;
      Fun_Info              : Exp_Record        := Null_Exp_Record;
   begin
      Actual_Type := Dictionary.GetType (Formal_Sym);
      -- The Actual_Type we have got here might be a predefined Ada type such as Integer.
      -- If so, then that is the type we expect the actual expression to be; however,
      -- if the type is a generic type then we need to look up the actual associated with it:
      if Dictionary.TypeIsGeneric (Actual_Type) then
         Actual_Type := Dictionary.ActualOfGenericFormalType (Actual_Type, Instantiation_Sym);
      end if;

      -- walk expression
      SeqAlgebra.CreateSeq (The_Heap, Unwanted_Seq);
      ComponentManager.Initialise (Unused_Component_Data);
      --# accept Flow, 10, Unused_Component_Data, "Expected ineffective assignment";
      Walk_Expression_P.Walk_Expression
        (Exp_Node                => Expression_Node,
         Scope                   => Scope,
         Type_Context            => Actual_Type,
         Context_Requires_Static => False,
         Ref_Var                 => Unwanted_Seq,
         Result                  => Exp_Result,
         Component_Data          => Unused_Component_Data,
         The_Heap                => The_Heap);
      --# end accept;
      SeqAlgebra.DisposeOfSeq (The_Heap, Unwanted_Seq);
      Maths.StorageRep (Exp_Result.Value, Value); -- scalar value if needed later

      -- check constant
      if Exp_Result.Is_Constant then
         if Exp_Result = Unknown_Type_Record then
            Error_Found := True;
         else
            -- Fundamentally ok to add
            -- mark any errors (both to avoid use of invalid instantiation and to supress rule generation)
            if Exp_Result.Errors_In_Expression then
               Error_Found := True;
            end if;
            --# accept Flow, 10, Fun_Info, "Ineffective assignment here OK";
            Wf_Argument_Association
              (Node        => STree.NullNode,
               Scope       => Scope,
               Param_Type  => Actual_Type,
               Position    => Node_Position (Node => Expression_Node),
               Exp_Result  => Exp_Result,
               Fun_Info    => Fun_Info,
               Error_Found => Error_Found);
            --# end accept;
            -- first add a constant declaration to local scope of Instantiation_Sym
            -- synthetic constant can have same name as formal it is associated with.
            -- Create a unique name for the actual object parameter:
            -- <instantiation_name>__<generic_formal_object_name>_.
            Constant_Name_String := LexTokenManager.Lex_String_To_String (Dictionary.GetSimpleName (Instantiation_Sym));
            E_Strings.Append_String (E_Str => Constant_Name_String,
                                     Str   => "__");
            E_Strings.Append_Examiner_String
              (E_Str1 => Constant_Name_String,
               E_Str2 => LexTokenManager.Lex_String_To_String (Dictionary.GetSimpleName (Formal_Sym)));
            E_Strings.Append_String (E_Str => Constant_Name_String,
                                     Str   => "_");
            LexTokenManager.Insert_Examiner_String (Str     => Constant_Name_String,
                                                    Lex_Str => Constant_Name);

            -- and can be "located" at expression node
            Constant_Location :=
              Dictionary.Location'
              (Start_Position => Node_Position (Node => Expression_Node),
               End_Position   => Node_Position (Node => Expression_Node));

            if Dictionary.IsArrayTypeMark (Actual_Type, Scope) then
               Value := LexTokenManager.Null_String;
            elsif Dictionary.IsPrivateTypeMark (Actual_Type, Scope) then
               Exp_Result.Is_Static := False;
            elsif Dictionary.IsRecordTypeMark (Actual_Type, Scope) or else Dictionary.IsProtectedTypeMark (Actual_Type) then
               Exp_Result.Is_Static := False;
               Value                := LexTokenManager.Null_String;
            end if;

            Dictionary.Add_Constant
              (Name              => Constant_Name,
               The_Type          => Actual_Type,
               Static            => Exp_Result.Is_Static,
               Comp_Unit         => ContextManager.Ops.Current_Unit,
               Declaration       => Constant_Location,
               Value             => Value,
               Exp_Is_Wellformed => not Exp_Result.Errors_In_Expression,
               Exp_Node          => STree.NodeToRef (Expression_Node),
               Constant_Sym      => Constant_Sym);
            STree.Add_Node_Symbol (Node => Expression_Node,
                                   Sym  => Constant_Sym);
            Dictionary.AddGenericObjectAssociation
              (SubprogramOrPackage => Instantiation_Sym,
               Comp_Unit           => ContextManager.Ops.Current_Unit,
               Declaration         => Dictionary.Location'(Start_Position => Node_Position (Node => Expression_Node),
                                                           End_Position   => Node_Position (Node => Expression_Node)),
               FormalSym           => Formal_Sym,
               ActualSym           => Constant_Sym);
         end if;
      else
         Error_Found := True;
         ErrorHandler.Semantic_Error
           (Err_Num   => 640,
            Reference => ErrorHandler.No_Reference,
            Position  => Node_Position (Node => Expression_Node),
            Id_Str    => LexTokenManager.Null_String);
      end if;
   end Process_Generic_Object_Parameter;

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

   procedure Handle_Named_Association
     (Named_Argument_Assoc_Node : in     STree.SyntaxNode;
      Instantiation_Sym         : in     Dictionary.Symbol;
      Scope                     : in     Dictionary.Scopes;
      Error_Found               : in out Boolean;
      Component_Data            : in out ComponentManager.ComponentData;
      The_Heap                  : in out Heap.HeapRecord)
   --# global in     CommandLineData.Content;
   --#        in     ContextManager.Ops.File_Heap;
   --#        in     ContextManager.Ops.Unit_Heap;
   --#        in     ContextManager.Ops.Unit_Stack;
   --#        in out Aggregate_Stack.State;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out LexTokenManager.State;
   --#        in out SLI.State;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --#        in out STree.Table;
   --# derives Aggregate_Stack.State,
   --#         Component_Data,
   --#         Dictionary.Dict,
   --#         Error_Found,
   --#         LexTokenManager.State,
   --#         Statistics.TableUsage,
   --#         STree.Table,
   --#         The_Heap                   from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         Error_Found,
   --#                                         Instantiation_Sym,
   --#                                         LexTokenManager.State,
   --#                                         Named_Argument_Assoc_Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         The_Heap &
   --#         ErrorHandler.Error_Context,
   --#         SLI.State,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.File_Heap,
   --#                                         ContextManager.Ops.Unit_Heap,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         Error_Found,
   --#                                         Instantiation_Sym,
   --#                                         LexTokenManager.State,
   --#                                         Named_Argument_Assoc_Node,
   --#                                         Scope,
   --#                                         SLI.State,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         The_Heap;
   --# pre Syntax_Node_Type (Named_Argument_Assoc_Node, STree.Table) = SP_Symbols.named_argument_association;
   --# post STree.Table = STree.Table~;
   is
      Formal_It               : Dictionary.Iterator;
      Generic_Sym, Formal_Sym : Dictionary.Symbol;
      Formal_Kind             : Dictionary.Generic_Parameter_Kind;
      Expression_Node         : STree.SyntaxNode;
   begin
      Generic_Sym := Dictionary.GetGenericOfInstantiation (PackageOrSubProgram => Instantiation_Sym);
      -- Check that each named assoication appears and appears once only
      Check_Named_Association (The_Formals               => Generic_Sym,
                               Scope                     => Scope,
                               Named_Argument_Assoc_Node => Named_Argument_Assoc_Node);

      -- now process each formal in turn
      Formal_It := Dictionary.FirstGenericFormalParameter (Generic_Sym);
      while not Dictionary.IsNullIterator (Formal_It) loop
         --# assert STree.Table = STree.Table~ and
         --#   Syntax_Node_Type (Named_Argument_Assoc_Node, STree.Table) = SP_Symbols.named_argument_association;
         Formal_Sym := Dictionary.CurrentSymbol (Formal_It);
         Find_Actual_Node
           (For_Formal                => Formal_Sym,
            Named_Argument_Assoc_Node => Named_Argument_Assoc_Node,
            Expression_Node           => Expression_Node);
         -- ASSUME Expression_Node = expression OR NULL
         --# check Syntax_Node_Type (Expression_Node, STree.Table) = SP_Symbols.expression or
         --#   Expression_Node = STree.NullNode;
         if Syntax_Node_Type (Node => Expression_Node) = SP_Symbols.expression then
            -- ASSUME Expression_Node = expression
            -- wff them together here
            Formal_Kind := Dictionary.GetGenericFormalParameterKind (Formal_Sym);
            case Formal_Kind is
               when Dictionary.Generic_Type_Parameter =>
                  Process_Generic_Type_Parameter
                    (Formal_Sym        => Formal_Sym,
                     Expression_Node   => Expression_Node,
                     Instantiation_Sym => Instantiation_Sym,
                     Scope             => Scope,
                     Error_Found       => Error_Found,
                     Component_Data    => Component_Data,
                     The_Heap          => The_Heap);
               when Dictionary.Generic_Object_Parameter =>
                  Process_Generic_Object_Parameter
                    (Formal_Sym        => Formal_Sym,
                     Expression_Node   => Expression_Node,
                     Instantiation_Sym => Instantiation_Sym,
                     Scope             => Scope,
                     Error_Found       => Error_Found,
                     The_Heap          => The_Heap);
            end case;
         end if;
         Formal_It := Dictionary.NextSymbol (Formal_It);
      end loop;
   end Handle_Named_Association;

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

   procedure Handle_Positional_Association
     (Positional_Argument_Assoc_Node : in     STree.SyntaxNode;
      Instantiation_Sym              : in     Dictionary.Symbol;
      Scope                          : in     Dictionary.Scopes;
      Error_Found                    : in out Boolean;
      Component_Data                 : in out ComponentManager.ComponentData;
      The_Heap                       : in out Heap.HeapRecord)
   --# global in     CommandLineData.Content;
   --#        in     ContextManager.Ops.File_Heap;
   --#        in     ContextManager.Ops.Unit_Heap;
   --#        in     ContextManager.Ops.Unit_Stack;
   --#        in out Aggregate_Stack.State;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out LexTokenManager.State;
   --#        in out SLI.State;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --#        in out STree.Table;
   --# derives Aggregate_Stack.State,
   --#         Component_Data,
   --#         Dictionary.Dict,
   --#         Error_Found,
   --#         LexTokenManager.State,
   --#         Statistics.TableUsage,
   --#         STree.Table,
   --#         The_Heap                   from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         Error_Found,
   --#                                         Instantiation_Sym,
   --#                                         LexTokenManager.State,
   --#                                         Positional_Argument_Assoc_Node,
   --#                                         Scope,
   --#                                         STree.Table,
   --#                                         The_Heap &
   --#         ErrorHandler.Error_Context,
   --#         SLI.State,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.File_Heap,
   --#                                         ContextManager.Ops.Unit_Heap,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         Error_Found,
   --#                                         Instantiation_Sym,
   --#                                         LexTokenManager.State,
   --#                                         Positional_Argument_Assoc_Node,
   --#                                         Scope,
   --#                                         SLI.State,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         The_Heap;
   --# pre Syntax_Node_Type (Positional_Argument_Assoc_Node, STree.Table) = SP_Symbols.positional_argument_association;
   --# post STree.Table = STree.Table~;
   is
      Formal_It               : Dictionary.Iterator;
      Actual_It               : STree.Iterator;
      Generic_Sym, Formal_Sym : Dictionary.Symbol;
      Formal_Kind             : Dictionary.Generic_Parameter_Kind;
      Expression_Node         : STree.SyntaxNode;
   begin
      Generic_Sym     := Dictionary.GetGenericOfInstantiation (PackageOrSubProgram => Instantiation_Sym);
      Expression_Node := Positional_Argument_Assoc_Node; -- default value in case loop below is skipped
      Actual_It       :=
        Find_First_Node
        (Node_Kind    => SP_Symbols.expression,
         From_Root    => Positional_Argument_Assoc_Node,
         In_Direction => STree.Down);
      Formal_It       := Dictionary.FirstGenericFormalParameter (Generic_Sym);

      while not Dictionary.IsNullIterator (Formal_It) and then not STree.IsNull (Actual_It) loop
         Formal_Sym      := Dictionary.CurrentSymbol (Formal_It);
         Expression_Node := Get_Node (It => Actual_It);
         --# assert Syntax_Node_Type (Expression_Node, STree.Table) = SP_Symbols.expression and
         --#   Expression_Node = Get_Node (Actual_It) and
         --#   STree.Table = STree.Table~ ;
         Formal_Kind := Dictionary.GetGenericFormalParameterKind (Formal_Sym);
         case Formal_Kind is
            when Dictionary.Generic_Type_Parameter =>
               Process_Generic_Type_Parameter
                 (Formal_Sym        => Formal_Sym,
                  Expression_Node   => Expression_Node,
                  Instantiation_Sym => Instantiation_Sym,
                  Scope             => Scope,
                  Error_Found       => Error_Found,
                  Component_Data    => Component_Data,
                  The_Heap          => The_Heap);
            when Dictionary.Generic_Object_Parameter =>
               Process_Generic_Object_Parameter
                 (Formal_Sym        => Formal_Sym,
                  Expression_Node   => Expression_Node,
                  Instantiation_Sym => Instantiation_Sym,
                  Scope             => Scope,
                  Error_Found       => Error_Found,
                  The_Heap          => The_Heap);
         end case;
         Formal_It := Dictionary.NextSymbol (Formal_It);
         Actual_It := STree.NextNode (Actual_It);
      end loop;

      -- completeness check, both loops should run out at same time
      if not Dictionary.IsNullIterator (Formal_It) or else not STree.IsNull (Actual_It) then
         Error_Found := True;
         ErrorHandler.Semantic_Error
           (Err_Num   => 635,
            Reference => ErrorHandler.No_Reference,
            Position  => Node_Position (Node => Expression_Node),
            Id_Str    => Dictionary.GetSimpleName (Generic_Sym));
      end if;
   end Handle_Positional_Association;

begin -- Wf_Generic_Actual_Part
   Error_Found  := False;
   Current_Node := Child_Node (Current_Node => Child_Node (Current_Node => Actual_Part_Node));
   -- ASSUME Current_Node = named_argument_association OR positional_argument_association
   if Syntax_Node_Type (Node => Current_Node) = SP_Symbols.named_argument_association then
      -- ASSUME Current_Node = named_argument_association
      Handle_Named_Association
        (Named_Argument_Assoc_Node => Current_Node,
         Instantiation_Sym         => Instantiation_Sym,
         Scope                     => Scope,
         Error_Found               => Error_Found,
         Component_Data            => Component_Data,
         The_Heap                  => The_Heap);
   elsif Syntax_Node_Type (Node => Current_Node) = SP_Symbols.positional_argument_association then
      -- ASSUME Current_Node = positional_argument_association
      Handle_Positional_Association
        (Positional_Argument_Assoc_Node => Current_Node,
         Instantiation_Sym              => Instantiation_Sym,
         Scope                          => Scope,
         Error_Found                    => Error_Found,
         Component_Data                 => Component_Data,
         The_Heap                       => The_Heap);
   else
      SystemErrors.Fatal_Error
        (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Current_Node = named_argument_association OR " &
           "positional_argument_association in Wf_Generic_Actual_Part");
   end if;
end Wf_Generic_Actual_Part;
