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

separate (Sem.Walk_Expression_P)
procedure Wf_Positional_Argument_Association
  (Node           : in out STree.SyntaxNode;
   Scope          : in     Dictionary.Scopes;
   Ref_Var        : in     SeqAlgebra.Seq;
   E_Stack        : in out Exp_Stack.Exp_Stack_Type;
   Component_Data : in out ComponentManager.ComponentData;
   The_Heap       : in out Heap.HeapRecord)
is

   Exp_Result, Type_Info         : Sem.Exp_Record;
   Expected_Type, Sym, Param_Sym : Dictionary.Symbol;
   Types_Are_Convertable         : Boolean;
   Exp_Value, Unused_Value       : Maths.Value;
   Error_Found                   : Boolean := False;

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

   procedure Chain_Up_To_Name_List (Node : in out STree.SyntaxNode)
   --# global in STree.Table;
   --# derives Node from *,
   --#                   STree.Table;
   --# pre STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.positional_argument_association or
   --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_positional_argument_association;
   --# post STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.name_argument_list or
   --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_name_argument_list;
   is
   begin
      while STree.Syntax_Node_Type (Node => Node) /= SP_Symbols.name_argument_list
        and then STree.Syntax_Node_Type (Node => Node) /= SP_Symbols.annotation_name_argument_list loop
         --# assert STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.positional_argument_association or
         --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_positional_argument_association;
         Node := STree.Parent_Node (Current_Node => Node);
         -- ASSUME Node = annotation_positional_argument_association OR annotation_name_argument_list OR
         --               positional_argument_association OR name_argument_list
         SystemErrors.RT_Assert
           (C       => STree.Syntax_Node_Type (Node => Node) = SP_Symbols.name_argument_list
              or else STree.Syntax_Node_Type (Node => Node) = SP_Symbols.positional_argument_association
              or else STree.Syntax_Node_Type (Node => Node) = SP_Symbols.annotation_name_argument_list
              or else STree.Syntax_Node_Type (Node => Node) = SP_Symbols.annotation_positional_argument_association,
            Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Node = annotation_positional_argument_association OR " &
              "annotation_name_argument_list OR positional_argument_association OR " &
              "name_argument_list in Chain_Up_To_Name_List");
      end loop;
   end Chain_Up_To_Name_List;

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

   procedure Check_Types_Are_Convertable
     (Node           : in     STree.SyntaxNode;
      Target, Source : in     Dictionary.Symbol;
      Scope          : in     Dictionary.Scopes;
      Ok             :    out Boolean)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     LexTokenManager.State;
   --#        in     STree.Table;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --# derives ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         Source,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         Target &
   --#         Ok                         from Dictionary.Dict,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Scope,
   --#                                         Source,
   --#                                         STree.Table,
   --#                                         Target;
   --# pre STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.positional_argument_association or
   --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_positional_argument_association;
   is
      Undefined : Boolean := False;

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

      function Dimensions_Match (Target, Source : Dictionary.Symbol) return Boolean
      --# global in Dictionary.Dict;
      is
      begin
         return Dictionary.GetNumberOfDimensions (Target) = Dictionary.GetNumberOfDimensions (Source);
      end Dimensions_Match;

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

      function Indexes_Are_Convertible (Target, Source : Dictionary.Symbol) return Boolean
      --# global in Dictionary.Dict;
      is
         Tgt_It, Src_It : Dictionary.Iterator;
         Ok             : Boolean;

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

         function Convertible (Src, Tgt : Dictionary.Symbol) return Boolean
         --# global in Dictionary.Dict;
         is
         begin
            return (Dictionary.TypeIsNumeric (Src) and then Dictionary.TypeIsNumeric (Tgt))
              or else Dictionary.Types_Are_Equal
              (Left_Symbol        => Dictionary.GetRootType (Src),
               Right_Symbol       => Dictionary.GetRootType (Tgt),
               Full_Range_Subtype => False);
         end Convertible;

      begin -- Indexes_Are_Convertible
         Ok     := True;
         Tgt_It := Dictionary.FirstArrayIndex (Target);
         Src_It := Dictionary.FirstArrayIndex (Source);
         while not Dictionary.IsNullIterator (Tgt_It) loop
            if not Convertible (Src => Dictionary.CurrentSymbol (Src_It),
                                Tgt => Dictionary.CurrentSymbol (Tgt_It)) then
               Ok := False;
               exit;
            end if;
            Tgt_It := Dictionary.NextSymbol (Tgt_It);
            Src_It := Dictionary.NextSymbol (Src_It);
         end loop;
         return Ok;
      end Indexes_Are_Convertible;

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

      function Components_Same_Type (Target, Source : Dictionary.Symbol) return Boolean
      --# global in Dictionary.Dict;
      is
      begin
         return Dictionary.Types_Are_Equal
           (Left_Symbol        => Dictionary.GetRootType (Dictionary.GetArrayComponent (Target)),
            Right_Symbol       => Dictionary.GetRootType (Dictionary.GetArrayComponent (Source)),
            Full_Range_Subtype => False);
      end Components_Same_Type;

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

      function Components_Constraints_Match (Target, Source : Dictionary.Symbol) return Boolean
      --# global in Dictionary.Dict;
      --#        in LexTokenManager.State;
      is
         Tgt_Component, Src_Component : Dictionary.Symbol;
         Result                       : Boolean;

         function Scalar_Bounds_Match (Tgt_Sym, Src_Sym : Dictionary.Symbol) return Boolean
         --# global in Dictionary.Dict;
         --#        in LexTokenManager.State;
         is
         begin
            return LexTokenManager.Lex_String_Case_Insensitive_Compare
              (Lex_Str1 => Dictionary.GetScalarAttributeValue (False, LexTokenManager.First_Token, Src_Sym),
               Lex_Str2 => Dictionary.GetScalarAttributeValue (False, LexTokenManager.First_Token, Tgt_Sym)) =
              LexTokenManager.Str_Eq
              and then LexTokenManager.Lex_String_Case_Insensitive_Compare
              (Lex_Str1 => Dictionary.GetScalarAttributeValue (False, LexTokenManager.Last_Token, Src_Sym),
               Lex_Str2 => Dictionary.GetScalarAttributeValue (False, LexTokenManager.Last_Token, Tgt_Sym)) =
              LexTokenManager.Str_Eq;
         end Scalar_Bounds_Match;

      begin -- Components_Constraints_Match
         Tgt_Component := Dictionary.GetArrayComponent (Target);
         Src_Component := Dictionary.GetArrayComponent (Source);
         if Dictionary.TypeIsScalar (Tgt_Component) then
            Result := Scalar_Bounds_Match (Tgt_Sym => Tgt_Component,
                                           Src_Sym => Src_Component);
         elsif Dictionary.TypeIsArray (Tgt_Component) then
            Result := Sem.Indexes_Match (Target => Tgt_Component,
                                         Source => Src_Component);
         else
            Result := Dictionary.TypeIsRecord (Tgt_Component);
         end if;
         return Result;
      end Components_Constraints_Match;

   begin -- Check_Types_Are_Convertable

      -- UnknownTypes considered convertable to stop error propagation
      if Dictionary.IsUnknownTypeMark (Target) or else Dictionary.IsUnknownTypeMark (Source) then
         Ok        := True;
         Undefined := True;
      elsif STree.Syntax_Node_Type (Node => Node) = SP_Symbols.positional_argument_association
        and then (Dictionary.IsPrivateType (Source, Scope) or else Dictionary.IsPrivateType (Target, Scope))
        and then not Dictionary.Types_Are_Equal (Left_Symbol        => Target,
                                                 Right_Symbol       => Source,
                                                 Full_Range_Subtype => False) then
         Ok := False;
      elsif Dictionary.TypeIsNumeric (Target) and then Dictionary.TypeIsNumeric (Source) then
         Ok := True;
      elsif Dictionary.TypeIsArray (Target) and then Dictionary.TypeIsArray (Source) then
         Ok := True;
         if not Dimensions_Match (Target => Target,
                                  Source => Source) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 423,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position (Node => Node),
               Id_Str    => LexTokenManager.Null_String);
            Ok := False;
         elsif not Indexes_Are_Convertible (Target => Target,
                                            Source => Source) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 420,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position (Node => Node),
               Id_Str    => LexTokenManager.Null_String);
            Ok := False;
         elsif not Sem.Indexes_Match (Target => Target,
                                      Source => Source) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 418,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position (Node => Node),
               Id_Str    => LexTokenManager.Null_String);
            Ok := False;
         elsif not Components_Same_Type (Target => Target,
                                         Source => Source) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 421,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position (Node => Node),
               Id_Str    => LexTokenManager.Null_String);
            Ok := False;
         elsif not Components_Constraints_Match (Target => Target,
                                                 Source => Source) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 422,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position (Node => Node),
               Id_Str    => LexTokenManager.Null_String);
            Ok := False;
         end if;

         -- allow unnecessary conversions, warning will be produced by later if clause
      else
         Ok :=
           Dictionary.Types_Are_Equal
           (Left_Symbol        => Dictionary.GetRootType (Target),
            Right_Symbol       => Dictionary.GetRootType (Source),
            Full_Range_Subtype => False);
      end if;

      -- if legal (other than undefined case, check if necessary)
      if Ok
        and then not Undefined
        and then Dictionary.Types_Are_Equal
        (Left_Symbol        => Dictionary.GetRootType (Target),
         Right_Symbol       => Dictionary.GetRootType (Source),
         Full_Range_Subtype => False) then
         ErrorHandler.Semantic_Warning
           (Err_Num  => 309,
            Position => STree.Node_Position
              (Node => STree.Parent_Node
                 (Current_Node => STree.Parent_Node (Current_Node => STree.Parent_Node (Current_Node => Node)))),
            Id_Str   => LexTokenManager.Null_String);
      end if;
   end Check_Types_Are_Convertable;

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

   procedure Do_Tagged_Type_Conversion
     (Node           : in     STree.SyntaxNode;
      Ref_Var        : in     SeqAlgebra.Seq;
      Target         : in out Sem.Exp_Record;
      Component_Data : in out ComponentManager.ComponentData;
      The_Heap       : in out Heap.HeapRecord;
      Source         : in     Sem.Exp_Record)
   --# global in     CommandLineData.Content;
   --#        in     ContextManager.Ops.Unit_Stack;
   --#        in     LexTokenManager.State;
   --#        in     STree.Table;
   --#        in out Dictionary.Dict;
   --#        in out ErrorHandler.Error_Context;
   --#        in out SPARK_IO.File_Sys;
   --#        in out Statistics.TableUsage;
   --# derives Component_Data,
   --#         Dictionary.Dict            from Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         Node,
   --#                                         Source,
   --#                                         STree.Table,
   --#                                         Target,
   --#                                         The_Heap &
   --#         ErrorHandler.Error_Context,
   --#         SPARK_IO.File_Sys          from CommandLineData.Content,
   --#                                         Dictionary.Dict,
   --#                                         ErrorHandler.Error_Context,
   --#                                         LexTokenManager.State,
   --#                                         Node,
   --#                                         Source,
   --#                                         SPARK_IO.File_Sys,
   --#                                         STree.Table,
   --#                                         Target &
   --#         Statistics.TableUsage,
   --#         The_Heap                   from *,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         Node,
   --#                                         Ref_Var,
   --#                                         Source,
   --#                                         STree.Table,
   --#                                         Target,
   --#                                         The_Heap &
   --#         Target                     from *,
   --#                                         CommandLineData.Content,
   --#                                         Component_Data,
   --#                                         ContextManager.Ops.Unit_Stack,
   --#                                         Dictionary.Dict,
   --#                                         Node,
   --#                                         Source,
   --#                                         STree.Table,
   --#                                         The_Heap;
   --# pre STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.positional_argument_association or
   --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_positional_argument_association;
   is

      procedure Raise_Error (Node   : in     STree.SyntaxNode;
                             Err_No : in     Natural;
                             Target :    out Sem.Exp_Record)
      --# global in     CommandLineData.Content;
      --#        in     Dictionary.Dict;
      --#        in     LexTokenManager.State;
      --#        in     STree.Table;
      --#        in out ErrorHandler.Error_Context;
      --#        in out SPARK_IO.File_Sys;
      --# derives ErrorHandler.Error_Context,
      --#         SPARK_IO.File_Sys          from CommandLineData.Content,
      --#                                         Dictionary.Dict,
      --#                                         ErrorHandler.Error_Context,
      --#                                         Err_No,
      --#                                         LexTokenManager.State,
      --#                                         Node,
      --#                                         SPARK_IO.File_Sys,
      --#                                         STree.Table &
      --#         Target                     from Dictionary.Dict;
      --# pre STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.positional_argument_association or
      --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_positional_argument_association;
      is
      begin
         Target := Sem.Unknown_Type_Record;
         ErrorHandler.Semantic_Error
           (Err_Num   => Err_No,
            Reference => ErrorHandler.No_Reference,
            Position  => STree.Node_Position
              (Node => STree.Parent_Node
                 (Current_Node => STree.Parent_Node (Current_Node => STree.Parent_Node (Current_Node => Node)))),
            Id_Str    => LexTokenManager.Null_String);
      end Raise_Error;

   begin -- Do_Tagged_Type_Conversion

      -- On entry we know Target.TypeSymbol is tagged.  If Source.TypeSymbol is not then we have some grossly
      -- malformed type conversion
      if not Dictionary.TypeIsTagged (Source.Type_Symbol) then
         Raise_Error (Node   => Node,
                      Err_No => 32,
                      Target => Target);
      elsif not Dictionary.IsAnExtensionOf (Target.Type_Symbol, Source.Type_Symbol) then
         Raise_Error (Node   => Node,
                      Err_No => 831,
                      Target => Target);
      else
         -- We have two tagged types and the target is an ancestor of the source; basically ok
         if Source.Is_AVariable or else Source.Is_Constant then
            -- we have an object to convert
            if STree.Syntax_Node_Type (Node => Node) = SP_Symbols.annotation_positional_argument_association
              or else Source.Is_Constant then
               -- In an annotation, or for a constant, all we need to is change
               -- the result type to that expected.
               Target.Sort                  := Sem.Type_Result;
               Target.Is_Constant           := Source.Is_Constant;
               Target.Is_Static             := Source.Is_Static
                 and then CommandLineData.Content.Language_Profile /= CommandLineData.SPARK83;
               Target.Other_Symbol          := Dictionary.NullSymbol;
               Target.Variable_Symbol       := Source.Variable_Symbol;
               Target.Is_AVariable          := Source.Is_AVariable;
               Target.Is_An_Entire_Variable := False;
            else
               -- In a normal expression with a variable and we need to convert
               -- appropriate record subcomponent symbols.

               -- We can't replace X with X.Inherit unless we add X's subcomponents first
               Sem.Add_Record_Sub_Components
                 (Record_Var_Sym  => Source.Variable_Symbol,
                  Record_Type_Sym => Dictionary.GetType (Source.Variable_Symbol),
                  Component_Data  => Component_Data,
                  The_Heap        => The_Heap);

               -- Set up Sem.Exp_Record
               Target.Variable_Symbol       :=
                 Sem.Convert_Tagged_Actual (Actual               => Source.Variable_Symbol,
                                            Tagged_Parameter_Sym => Target.Type_Symbol);
               Target.Sort                  := Sem.Type_Result;
               Target.Is_Constant           := Source.Is_Constant;
               Target.Is_Static             := Source.Is_Static
                 and then CommandLineData.Content.Language_Profile /= CommandLineData.SPARK83;
               Target.Other_Symbol          := Dictionary.NullSymbol;
               Target.Is_AVariable          := Source.Is_AVariable;
               Target.Is_An_Entire_Variable := False;

               -- Substitute reference variables to show we only used a subcomponent of Source.
               -- We have to look for the source variable because there may be other items in
               -- the Ref_Var list if, for example, the type conversion forms part of a larger
               -- expression such as a function call.
               SeqAlgebra.RemoveMember (The_Heap, Ref_Var, Natural (Dictionary.SymbolRef (Source.Variable_Symbol)));
               SeqAlgebra.AddMember (The_Heap, Ref_Var, Natural (Dictionary.SymbolRef (Target.Variable_Symbol)));
            end if;
         else -- not an object
            Raise_Error (Node   => Node,
                         Err_No => 832,
                         Target => Target);
         end if;
      end if;
   end Do_Tagged_Type_Conversion;

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

   function Convert_Value (Target : Dictionary.Symbol;
                           Exp    : Sem.Exp_Record) return Maths.Value
   --# global in CommandLineData.Content;
   --#        in Dictionary.Dict;
   is
      Val : Maths.Value;
   begin
      Val := Exp.Value;
      if not Maths.HasNoValue (Val) then
         if Dictionary.IsUnknownTypeMark (Target) then
            Val := Maths.NoValue;
         elsif Dictionary.TypeIsReal (Target) then
            Maths.ConvertToReal (Val);
         elsif Dictionary.TypeIsInteger (Target) and then Dictionary.TypeIsReal (Exp.Type_Symbol) then
            case CommandLineData.Content.Language_Profile is
               when CommandLineData.SPARK83 =>
                  Val := Maths.NoValue; -- can't do real to integer safely
               when CommandLineData.SPARK95_Onwards =>
                  Val := Maths.Ada95RealToInteger (Val);
            end case;
         end if;
      end if;
      return Val;
   end Convert_Value;

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

   function Expression_Location (Node : STree.SyntaxNode) return LexTokenManager.Token_Position
   --# global in STree.Table;
   --# pre STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.positional_argument_association or
   --#   STree.Syntax_Node_Type (Node, STree.Table) = SP_Symbols.annotation_positional_argument_association;
   is
      Result : STree.SyntaxNode;
   begin
      Result := STree.Child_Node (Current_Node => Node);
      -- ASSUME Result = annotation_positional_argument_association OR annotation_expression OR
      --                 positional_argument_association OR expression
      if STree.Syntax_Node_Type (Node => Result) = SP_Symbols.expression
        or else STree.Syntax_Node_Type (Node => Result) = SP_Symbols.annotation_expression then
         -- ASSUME Result = expression OR annotation_expression
         Result := Node;
         -- ASSUME Result = positional_argument_association OR annotation_positional_argument_association
      elsif STree.Syntax_Node_Type (Node => Result) = SP_Symbols.positional_argument_association
        or else STree.Syntax_Node_Type (Node => Result) = SP_Symbols.annotation_positional_argument_association then
         -- ASSUME Result = positional_argument_association OR annotation_positional_argument_association
         Result := STree.Next_Sibling (Current_Node => Result);
         -- ASSUME Result = expression OR annotation_expression
         SystemErrors.RT_Assert
           (C       => STree.Syntax_Node_Type (Node => Result) = SP_Symbols.expression
              or else STree.Syntax_Node_Type (Node => Result) = SP_Symbols.annotation_expression,
            Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Result = annotation_expression OR expression in Expression_Location");
      else
         SystemErrors.Fatal_Error
           (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
            Msg     => "Expect Result = annotation_positional_argument_association OR annotation_expression OR " &
              "positional_argument_association OR expression in Expression_Location");
      end if;
      return STree.Node_Position (Node => Result);
   end Expression_Location;

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

   function Get_Expected_Array_Index_Type
     (Var_Sym   : Dictionary.Symbol;
      Type_Sym  : Dictionary.Symbol;
      Dimension : Positive;
      Scope     : Dictionary.Scopes)
     return      Dictionary.Symbol
   --# global in Dictionary.Dict;
   --# return S => (Dictionary.Is_Null_Symbol (S) or
   --#                Dictionary.IsTypeMark (S, Dictionary.Dict) or
   --#                Dictionary.IsParameterConstraint (S, Dictionary.Dict));
   is
      Result : Dictionary.Symbol;
   begin
      -- This function determines what type to plant in the syntax tree so that the VCG can check
      -- that array accesses are in bounds.  FOr a constrained object it is edy - we plant the
      -- appropriate index type for the dimension being accessed.  For indexing into unconstrained
      -- objects we plant a symbol of a special kind (ParameterConstraintSymbol) associated with
      -- the array object (rather than its type); this special symbol represents "the index as
      -- constrained by 'something' at this point".  Typically we will no know the actual bounds
      -- of the constraint represented by this symbol.

      if Dictionary.Is_Unconstrained_Array_Type_Mark (Type_Sym, Scope) then
         -- For unconstrained arrays, obtain the implcitly declared constraint symbol for the array object
         Result := Dictionary.GetSubprogramParameterConstraint (Var_Sym, Dimension);
         if Dictionary.Is_Null_Symbol (Result) then
            Result := Dictionary.GetUnknownTypeMark;
         end if;
      else
         -- For constrained arrays then obtain appropriate index for the array type; this is what the VCG needs
         Result := Dictionary.GetArrayIndex (Type_Sym, Dimension);
      end if;
      return Result;
   end Get_Expected_Array_Index_Type;

begin -- Wf_Positional_Argument_Association
   Exp_Stack.Pop (Item  => Exp_Result,
                  Stack => E_Stack);
   Exp_Stack.Pop (Item  => Type_Info,
                  Stack => E_Stack);
   Sym := Type_Info.Other_Symbol;
   case Type_Info.Sort is
      when Sem.Is_Type_Mark =>
         -- seed syntax tree with type for run-time check
         STree.Add_Node_Symbol (Node => Node,
                                Sym  => Exp_Result.Type_Symbol);
         if Dictionary.Is_Unconstrained_Array_Type_Mark (Type_Info.Type_Symbol, Scope) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 39,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position
                 (Node => STree.Parent_Node
                    (Current_Node => STree.Parent_Node (Current_Node => STree.Parent_Node (Current_Node => Node)))),
               Id_Str    => LexTokenManager.Null_String);
            Type_Info := Sem.Unknown_Type_Record;
            -- special handling for type conversion of string literals.
         elsif Dictionary.IsPredefinedStringType (Exp_Result.Type_Symbol) and then Exp_Result.Range_RHS /= Maths.NoValue then
            ErrorHandler.Semantic_Error
              (Err_Num   => 425,
               Reference => 22,
               Position  => STree.Node_Position (Node => Node),
               Id_Str    => LexTokenManager.Null_String);
            Type_Info := Sem.Unknown_Type_Record;
         elsif Dictionary.TypeIsTagged (Type_Info.Type_Symbol) then
            Do_Tagged_Type_Conversion
              (Node           => Node,
               Ref_Var        => Ref_Var,
               Target         => Type_Info,
               Component_Data => Component_Data,
               The_Heap       => The_Heap,
               Source         => Exp_Result);
         else -- some "normal" conversion case
            if Exp_Result.Is_ARange then
               -- Type conversion of a range is illegal.  This also
               -- catches the illegal case of type-conversion of a
               -- subtype mark, such as Integer (Natural)
               ErrorHandler.Semantic_Error
                 (Err_Num   => 114,
                  Reference => ErrorHandler.No_Reference,
                  Position  => STree.Node_Position (Node => STree.Parent_Node (Current_Node => Node)),
                  Id_Str    => LexTokenManager.Null_String);
               Type_Info := Sem.Unknown_Type_Record;
            else
               Check_Types_Are_Convertable
                 (Node   => Node,
                  Target => Type_Info.Type_Symbol,
                  Source => Exp_Result.Type_Symbol,
                  Scope  => Scope,
                  Ok     => Types_Are_Convertable);
               if Types_Are_Convertable then
                  Sem.Constraint_Check
                    (Val           => Exp_Result.Value,
                     New_Val       => Exp_Value,
                     Is_Annotation => STree.Syntax_Node_Type (Node => Node) =
                       SP_Symbols.annotation_positional_argument_association,
                     Typ           => Type_Info.Type_Symbol,
                     Position      => STree.Node_Position (Node => Node));
                  Exp_Result.Value                := Exp_Value;
                  Type_Info.Sort                  := Sem.Type_Result;
                  Type_Info.Is_Constant           := Exp_Result.Is_Constant;
                  Type_Info.Is_Static             := Exp_Result.Is_Static
                    and then CommandLineData.Content.Language_Profile /= CommandLineData.SPARK83;
                  Type_Info.Other_Symbol          := Dictionary.NullSymbol;
                  Type_Info.Value                 := Convert_Value (Target => Type_Info.Type_Symbol,
                                                                    Exp    => Exp_Result);
                  Type_Info.Variable_Symbol       := Exp_Result.Variable_Symbol;
                  Type_Info.Is_AVariable          := False;
                  Type_Info.Is_An_Entire_Variable := False;
               else
                  ErrorHandler.Semantic_Error
                    (Err_Num   => 32,
                     Reference => ErrorHandler.No_Reference,
                     Position  => STree.Node_Position
                       (Node => STree.Parent_Node
                          (Current_Node => STree.Parent_Node (Current_Node => STree.Parent_Node (Current_Node => Node)))),
                     Id_Str    => LexTokenManager.Null_String);
                  Type_Info := Sem.Unknown_Type_Record;
               end if;
            end if;
         end if;
      when Sem.Is_Function =>
         if Type_Info.Param_Count >= Dictionary.GetNumberOfSubprogramParameters (Sym) then
            Type_Info := Unknown_Symbol_Record;
            ErrorHandler.Semantic_Error
              (Err_Num   => 3,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position (Node => Node),
               Id_Str    => Dictionary.GetSimpleName (Sym));
            Chain_Up_To_Name_List (Node => Node);
         else
            Type_Info.Param_Count := Type_Info.Param_Count + 1;
            Param_Sym             := Dictionary.GetSubprogramParameter (Sym, Type_Info.Param_Count);
            Expected_Type         := Dictionary.GetType (Param_Sym);
            -- Seed syntax tree with expected type for run-time check;
            -- but, don't do this for instantiation of unchecked_conversion
            -- because we don't want any RTCs for association of those parameters
            -- (provided the function parameter subtype and actual subtype match)
            if not (Dictionary.IsAnUncheckedConversion (Sym)
                      and then Dictionary.Types_Are_Equal
                      (Left_Symbol        => Exp_Result.Type_Symbol,
                       Right_Symbol       => Expected_Type,
                       Full_Range_Subtype => False)) then
               STree.Add_Node_Symbol (Node => Node,
                                      Sym  => Expected_Type);
            end if;
            -- There is a special case involving functions an stream variables.  We allow a stream
            -- variable to be a parameter to an Unchecked_Conversion but need to ensure that
            -- the function inherits the restrictions associated with referencing a stream
            -- (e.g. cannot be used in general expression).  We can do this here by checking
            -- the StreamSymbol of the parameter expression (there will only be one if we are
            -- talking about an unchecked conversion) and if it is non-null then setting the
            -- stream symbol of the function result record (now an object) to the function symbol.
            -- Note that this clause will only be executed for an unchecked conversion because
            -- a parameter which is a stream would hav ebeen rejected at wf_primary in all other
            -- cases
            if not Dictionary.Is_Null_Symbol (Exp_Result.Stream_Symbol) then
               Type_Info.Stream_Symbol := Sym;
            end if;
            Sem.Wf_Argument_Association
              (Node        => Node,
               Scope       => Scope,
               Param_Type  => Dictionary.GetType (Param_Sym),
               Position    => Expression_Location (Node => Node),
               Exp_Result  => Exp_Result,
               Fun_Info    => Type_Info,
               Error_Found => Error_Found);
         end if;
      when Sem.Is_Object =>
         if Type_Info.Param_Count >= Dictionary.GetNumberOfDimensions (Type_Info.Type_Symbol) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 93,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position (Node => Node),
               Id_Str    => Dictionary.GetSimpleName (Sym));
            Type_Info := Unknown_Symbol_Record;
            Chain_Up_To_Name_List (Node => Node);
         else
            Type_Info.Param_Count := Type_Info.Param_Count + 1;
            -- Expected_Type is used to ensure that indexing expression is well-typed
            Expected_Type := Dictionary.GetArrayIndex (Type_Info.Type_Symbol, Type_Info.Param_Count);
            -- VCG_Type is used to tell VCG what indexing type to expect.  Same as Expected type for a
            -- constrained array but different for unconstrained.  See comment in function Get_Expected_Array_Index_Type
            -- seed syntax tree with expected type for run-time check
            STree.Add_Node_Symbol
              (Node => Node,
               Sym  => Get_Expected_Array_Index_Type
                 (Var_Sym   => Type_Info.Other_Symbol,
                  Type_Sym  => Type_Info.Type_Symbol,
                  Dimension => Type_Info.Param_Count,
                  Scope     => Scope));
            Sem.Range_Check
              (A_Range     => Exp_Result.Is_ARange,
               Position    => Expression_Location (Node => Node),
               Error_Found => Error_Found);
            Type_Info.Is_Constant := Type_Info.Is_Constant and then Exp_Result.Is_Constant;
            if Dictionary.CompatibleTypes (Scope, Expected_Type, Exp_Result.Type_Symbol) then
               --# accept Flow, 10, Unused_Value, "Expected ineffective assignment";
               Sem.Constraint_Check
                 (Val           => Exp_Result.Value,
                  New_Val       => Unused_Value,
                  Is_Annotation => STree.Syntax_Node_Type (Node => Node) = SP_Symbols.annotation_positional_argument_association,
                  Typ           => Expected_Type,
                  Position      => Expression_Location (Node => Node));
               --# end accept;
            else
               Error_Found := True;
               ErrorHandler.Semantic_Error
                 (Err_Num   => 38,
                  Reference => ErrorHandler.No_Reference,
                  Position  => Expression_Location (Node => Node),
                  Id_Str    => LexTokenManager.Null_String);
            end if;
         end if;
      when others =>
         null;
   end case;
   Type_Info.Errors_In_Expression := Error_Found or else Type_Info.Errors_In_Expression or else Exp_Result.Errors_In_Expression;
   Exp_Stack.Push (X     => Type_Info,
                   Stack => E_Stack);
   --# accept Flow, 33, Unused_Value, "Expected to be neither referenced nor exported";
end Wf_Positional_Argument_Association;
