-------------------------------------------------------------------------------
-- (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_Aggregate_Choice
  (Node    : in     STree.SyntaxNode;
   Scope   : in     Dictionary.Scopes;
   E_Stack : in out Exp_Stack.Exp_Stack_Type)
is

   type Case_Choice_Sorts is (Single_Expression, Explicit_Range, Range_Constraint);

   Case_Choice_Sort                                           : Case_Choice_Sorts;
   First_Node, Second_Node                                    : STree.SyntaxNode;
   Name_Exp, First_Result, Second_Result                      : Sem.Exp_Record;
   Semantic_Errors_Found                                      : Boolean            := False;
   Choice_Lower_Maths_Value                                   : Maths.Value;
   Choice_Upper_Maths_Value                                   : Maths.Value        := Maths.NoValue;
   Is_A_Range                                                 : Boolean;
   Index_Type_Symbol                                          : Dictionary.Symbol;
   Index_Type_Lower_Bound, Index_Type_Upper_Bound             : Sem.Typ_Type_Bound;
   Aggregate_Flags                                            : Sem.Typ_Agg_Flags;
   Entry_Counter                                              : Natural;
   Complete_Rec                                               : CompleteCheck.T;
   Choice_Lower_Bound, Choice_Upper_Bound                     : Sem.Typ_Type_Bound := Sem.Unknown_Type_Bound;
   Lower_Bound_Unknown                                        : Boolean;
   Upper_Bound_Unknown                                        : Boolean            := True;
   Lower_Bound_Out_Of_Range                                   : Boolean;
   Upper_Bound_Out_Of_Range                                   : Boolean            := True;
   Out_Of_Range_Seen                                          : Boolean;
   Overlap_Seen                                               : CompleteCheck.TypOverlapState;
   Both_Choice_Bounds_Known                                   : Boolean            := False;
   Range_Constraint_Lower_Bound, Range_Constraint_Upper_Bound : Sem.Typ_Type_Bound;

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

   procedure Convert_Choice_Bound
     (Maths_Value        : in     Maths.Value;
      Bound              :    out Sem.Typ_Type_Bound;
      Unknown_Bound      :    out Boolean;
      Bound_Out_Of_Range :    out Boolean)
   --# derives Bound,
   --#         Bound_Out_Of_Range,
   --#         Unknown_Bound      from Maths_Value;
   --# post Bound.Is_Defined <-> (not Unknown_Bound and not Bound_Out_Of_Range);
   is
      Int         : Integer;
      Maths_Error : Maths.ErrorCode;
   begin
      if Maths.HasNoValue (Maths_Value) then
         Bound              := Sem.Typ_Type_Bound'(Value      => 0,
                                                   Is_Defined => False);
         Unknown_Bound      := True;
         Bound_Out_Of_Range := False;
      else
         Maths.ValueToInteger (Maths_Value, Int, Maths_Error);
         if Maths_Error = Maths.NoError then
            Bound              := Sem.Typ_Type_Bound'(Value      => Int,
                                                      Is_Defined => True);
            Unknown_Bound      := False;
            Bound_Out_Of_Range := False;
         else
            Bound              := Sem.Typ_Type_Bound'(Value      => 0,
                                                      Is_Defined => False);
            Unknown_Bound      := False;
            Bound_Out_Of_Range := True;
         end if;
      end if;
   end Convert_Choice_Bound;

   ------------------------------------------------------------------------
   -- note: returns True if any of the bounds is undefined, unless the
   -- choice is not a range, in which case, Choice_Upper is unused
   function Is_Choice_In_Range
     (Choice_Lower    : Sem.Typ_Type_Bound;
      Choice_Upper    : Sem.Typ_Type_Bound;
      Choice_Is_Range : Boolean;
      Range_Lower     : Sem.Typ_Type_Bound;
      Range_Upper     : Sem.Typ_Type_Bound)
     return            Boolean
   is
      Result : Boolean;
   begin
      if (Choice_Lower.Is_Defined and then Range_Lower.Is_Defined and then Choice_Lower.Value < Range_Lower.Value)
        or else (Choice_Lower.Is_Defined and then Range_Upper.Is_Defined and then Choice_Lower.Value > Range_Upper.Value)
        or else (Choice_Is_Range
                   and then Choice_Upper.Is_Defined
                   and then Range_Upper.Is_Defined
                   and then Choice_Upper.Value > Range_Upper.Value) then
         Result := False;
      else
         Result := True;
      end if;
      return Result;
   end Is_Choice_In_Range;

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

   function Is_Range_Empty (Range_Lower : Sem.Typ_Type_Bound;
                            Range_Upper : Sem.Typ_Type_Bound) return Boolean
   --# pre Range_Lower.Is_Defined and Range_Upper.Is_Defined;
   --# return not (Range_Lower.Value <= Range_Upper.Value);
   is
   begin
      return not (Range_Lower.Value <= Range_Upper.Value);
   end Is_Range_Empty;

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

   procedure Convert_Boolean_Maths_Value (Value : in out Maths.Value)
   --# derives Value from *;
   is
   begin
      if Value = Maths.FalseValue then
         Value := Maths.ZeroInteger;
      elsif Value = Maths.TrueValue then
         Value := Maths.OneInteger;
      end if;
   end Convert_Boolean_Maths_Value;

begin -- Wf_Aggregate_Choice

   -- Assume aggregate is array aggregate with named association
   Aggregate_Stack.Pop
     (Type_Sym     => Index_Type_Symbol,
      Lower_Bound  => Index_Type_Lower_Bound,
      Upper_Bound  => Index_Type_Upper_Bound,
      Agg_Flags    => Aggregate_Flags,
      Counter      => Entry_Counter,
      Complete_Rec => Complete_Rec);

   First_Node := STree.Child_Node (Current_Node => Node);
   -- ASSUME First_Node = simple_expression OR annotation_simple_expression
   SystemErrors.RT_Assert
     (C       => STree.Syntax_Node_Type (Node => First_Node) = SP_Symbols.simple_expression
        or else STree.Syntax_Node_Type (Node => First_Node) = SP_Symbols.annotation_simple_expression,
      Sys_Err => SystemErrors.Invalid_Syntax_Tree,
      Msg     => "Expect First_Node = simple_expression OR annotation_simple_expression in Wf_Aggregate_Choice");
   Second_Node := STree.Next_Sibling (Current_Node => First_Node);
   -- ASSUME Second_Node = range_constraint OR simple_expression OR
   --                      annotation_range_constraint OR annotation_simple_expression OR NULL
   if Second_Node = STree.NullNode then
      -- ASSUME Second_Node = NULL
      Case_Choice_Sort := Single_Expression;
   elsif STree.Syntax_Node_Type (Node => Second_Node) = SP_Symbols.simple_expression
     or else STree.Syntax_Node_Type (Node => Second_Node) = SP_Symbols.annotation_simple_expression then
      -- ASSUME Second_Node = simple_expression OR annotation_simple_expression
      Case_Choice_Sort := Explicit_Range;
   elsif STree.Syntax_Node_Type (Node => Second_Node) = SP_Symbols.range_constraint
     or else STree.Syntax_Node_Type (Node => Second_Node) = SP_Symbols.annotation_range_constraint then
      -- ASSUME Second_Node = range_constraint OR annotation_range_constraint
      Case_Choice_Sort := Range_Constraint;
   else
      Case_Choice_Sort := Single_Expression;
      SystemErrors.Fatal_Error
        (Sys_Err => SystemErrors.Invalid_Syntax_Tree,
         Msg     => "Expect Second_Node = range_constraint OR simple_expression OR annotation_range_constraint OR" &
           " annotation_simple_expression OR NULL in Wf_Aggregate_Choice");
   end if;

   --# assert (STree.Syntax_Node_Type (First_Node, STree.Table) = SP_Symbols.simple_expression or
   --#           STree.Syntax_Node_Type (First_Node, STree.Table) = SP_Symbols.annotation_simple_expression) and
   --#   (STree.Syntax_Node_Type (Second_Node, STree.Table) = SP_Symbols.range_constraint or
   --#      STree.Syntax_Node_Type (Second_Node, STree.Table) = SP_Symbols.simple_expression or
   --#      STree.Syntax_Node_Type (Second_Node, STree.Table) = SP_Symbols.annotation_range_constraint or
   --#      STree.Syntax_Node_Type (Second_Node, STree.Table) = SP_Symbols.annotation_simple_expression or
   --#      Second_Node = STree.NullNode) and
   --#   Aggregate_Stack.Stack_Is_Valid (Aggregate_Stack.State) and
   --#   ((Index_Type_Lower_Bound.Is_Defined and Index_Type_Upper_Bound.Is_Defined) ->
   --#      (Index_Type_Lower_Bound.Value <= Index_Type_Upper_Bound.Value)) and
   --#   (Complete_Rec.ActualUpperBound - Complete_Rec.LowerBound < ExaminerConstants.CompleteCheckSize) and
   --#   (Dictionary.Is_Null_Symbol (Index_Type_Symbol) or Dictionary.IsTypeMark (Index_Type_Symbol, Dictionary.Dict));

   case Case_Choice_Sort is
      when Single_Expression =>
         Exp_Stack.Pop (Item  => First_Result,
                        Stack => E_Stack);
         Exp_Stack.Pop (Item  => Name_Exp,
                        Stack => E_Stack);
         if Dictionary.IsUnknownTypeMark (First_Result.Type_Symbol) then
            null;
         elsif Name_Exp.Param_Count > 0
           and then Dictionary.CompatibleTypes
           (Scope,
            First_Result.Type_Symbol,
            Dictionary.GetArrayIndex (Name_Exp.Type_Symbol, Name_Exp.Param_Count)) then
            if not First_Result.Is_Static then
               ErrorHandler.Semantic_Error
                 (Err_Num   => 36,
                  Reference => 1,
                  Position  => STree.Node_Position (Node => First_Node),
                  Id_Str    => LexTokenManager.Null_String);
               Semantic_Errors_Found := True;
            end if;
         else
            ErrorHandler.Semantic_Error
              (Err_Num   => 38,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position (Node => First_Node),
               Id_Str    => LexTokenManager.Null_String);
            Semantic_Errors_Found := True;
         end if;
         -- code to work out whether we have a single choice or a
         -- range and to collect the appropriate values
         -- note that these will be nonsense if semantic errors have been found
         Choice_Lower_Maths_Value := First_Result.Value;
         if First_Result.Is_ARange then
            Is_A_Range               := True;
            Choice_Upper_Maths_Value := First_Result.Range_RHS;
         else
            Is_A_Range := False;
         end if;
         Name_Exp.Errors_In_Expression := Semantic_Errors_Found
           or else Name_Exp.Errors_In_Expression
           or else First_Result.Errors_In_Expression;
      when Explicit_Range =>
         Exp_Stack.Pop (Item  => Second_Result,
                        Stack => E_Stack);
         Exp_Stack.Pop (Item  => First_Result,
                        Stack => E_Stack);
         Exp_Stack.Pop (Item  => Name_Exp,
                        Stack => E_Stack);
         if not Dictionary.CompatibleTypes (Scope, First_Result.Type_Symbol, Second_Result.Type_Symbol) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 42,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position (Node => Second_Node),
               Id_Str    => LexTokenManager.Null_String);
            Semantic_Errors_Found := True;
         elsif Name_Exp.Param_Count > 0
           and then not Dictionary.CompatibleTypes
           (Scope,
            First_Result.Type_Symbol,
            Dictionary.GetArrayIndex (Name_Exp.Type_Symbol, Name_Exp.Param_Count)) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 106,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position (Node => First_Node),
               Id_Str    => LexTokenManager.Null_String);
            Semantic_Errors_Found := True;
         end if;
         if not (First_Result.Is_Static and then Second_Result.Is_Static) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 45,
               Reference => 1,
               Position  => STree.Node_Position (Node => First_Node),
               Id_Str    => LexTokenManager.Null_String);
            Semantic_Errors_Found := True;
         end if;
         -- code to collect the appropriate values for the extent of the range
         -- note that these will be nonsense if semantic errors have been found#
         Choice_Lower_Maths_Value      := First_Result.Value;
         Choice_Upper_Maths_Value      := Second_Result.Value;
         Is_A_Range                    := True;
         Name_Exp.Errors_In_Expression := Semantic_Errors_Found
           or else Name_Exp.Errors_In_Expression
           or else First_Result.Errors_In_Expression
           or else Second_Result.Errors_In_Expression;

      when Range_Constraint =>
         Exp_Stack.Pop (Item  => Second_Result,
                        Stack => E_Stack);
         Exp_Stack.Pop (Item  => First_Result,
                        Stack => E_Stack);
         Exp_Stack.Pop (Item  => Name_Exp,
                        Stack => E_Stack);
         if not Dictionary.CompatibleTypes (Scope, First_Result.Type_Symbol, Second_Result.Type_Symbol) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 106,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position (Node => Second_Node),
               Id_Str    => LexTokenManager.Null_String);
            Semantic_Errors_Found := True;
         elsif Name_Exp.Param_Count > 0
           and then not Dictionary.CompatibleTypes
           (Scope,
            First_Result.Type_Symbol,
            Dictionary.GetArrayIndex (Name_Exp.Type_Symbol, Name_Exp.Param_Count)) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 38,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position (Node => First_Node),
               Id_Str    => LexTokenManager.Null_String);
            Semantic_Errors_Found := True;
         end if;
         if not (First_Result.Is_Constant and then First_Result.Is_ARange) then
            ErrorHandler.Semantic_Error
              (Err_Num   => 95,
               Reference => ErrorHandler.No_Reference,
               Position  => STree.Node_Position (Node => First_Node),
               Id_Str    => LexTokenManager.Null_String);
            Semantic_Errors_Found := True;
         end if;
         if not Second_Result.Is_Static then
            ErrorHandler.Semantic_Error
              (Err_Num   => 45,
               Reference => 1,
               Position  => STree.Node_Position (Node => Second_Node),
               Id_Str    => LexTokenManager.Null_String);
            Semantic_Errors_Found := True;
         end if;
         -- code to collect the appropriate values for the extent of the range
         -- note that these will be nonsense if semantic errors have been found
         Choice_Lower_Maths_Value      := Second_Result.Value;
         Choice_Upper_Maths_Value      := Second_Result.Range_RHS;
         Is_A_Range                    := True;
         Name_Exp.Errors_In_Expression := Semantic_Errors_Found
           or else Name_Exp.Errors_In_Expression
           or else First_Result.Errors_In_Expression
           or else Second_Result.Errors_In_Expression;
         -- somewhere need to check that Second_Result range is within the type
         -- given by First_Result
   end case;

   Exp_Stack.Push (X     => Name_Exp,
                   Stack => E_Stack);

   --# assert (STree.Syntax_Node_Type (First_Node, STree.Table) = SP_Symbols.simple_expression or
   --#           STree.Syntax_Node_Type (First_Node, STree.Table) = SP_Symbols.annotation_simple_expression) and
   --#   (STree.Syntax_Node_Type (Second_Node, STree.Table) = SP_Symbols.range_constraint or
   --#      STree.Syntax_Node_Type (Second_Node, STree.Table) = SP_Symbols.simple_expression or
   --#      STree.Syntax_Node_Type (Second_Node, STree.Table) = SP_Symbols.annotation_range_constraint or
   --#      STree.Syntax_Node_Type (Second_Node, STree.Table) = SP_Symbols.annotation_simple_expression or
   --#      Second_Node = STree.NullNode) and
   --#   Aggregate_Stack.Stack_Is_Valid (Aggregate_Stack.State) and
   --#   ((Index_Type_Lower_Bound.Is_Defined and Index_Type_Upper_Bound.Is_Defined) ->
   --#      (Index_Type_Lower_Bound.Value <= Index_Type_Upper_Bound.Value)) and
   --#   (Complete_Rec.ActualUpperBound - Complete_Rec.LowerBound < ExaminerConstants.CompleteCheckSize) and
   --#   (Dictionary.Is_Null_Symbol (Index_Type_Symbol) or Dictionary.IsTypeMark (Index_Type_Symbol, Dictionary.Dict));

   if not Semantic_Errors_Found then
      Convert_Boolean_Maths_Value (Value => Choice_Lower_Maths_Value);
      Convert_Choice_Bound
        (Maths_Value        => Choice_Lower_Maths_Value,
         Bound              => Choice_Lower_Bound,
         Unknown_Bound      => Lower_Bound_Unknown,
         Bound_Out_Of_Range => Lower_Bound_Out_Of_Range);
      if Is_A_Range then
         Convert_Boolean_Maths_Value (Value => Choice_Upper_Maths_Value);  -- CUMV always defined here
         Convert_Choice_Bound
           (Maths_Value        => Choice_Upper_Maths_Value,
            Bound              => Choice_Upper_Bound,
            Unknown_Bound      => Upper_Bound_Unknown,
            Bound_Out_Of_Range => Upper_Bound_Out_Of_Range);
      else
         Choice_Upper_Bound := Sem.Unknown_Type_Bound;
      end if;

      if Lower_Bound_Out_Of_Range or else (Is_A_Range and then Upper_Bound_Out_Of_Range) then
         Both_Choice_Bounds_Known := False;
         ErrorHandler.Semantic_Warning
           (Err_Num  => 305,
            Position => STree.Node_Position (Node => First_Node),
            Id_Str   => LexTokenManager.Null_String);
      elsif Lower_Bound_Unknown or else (Is_A_Range and then Upper_Bound_Unknown) then
         Both_Choice_Bounds_Known    := False;
         Complete_Rec.Undeterminable := True;
         ErrorHandler.Semantic_Warning
           (Err_Num  => 200,
            Position => STree.Node_Position (Node => First_Node),
            Id_Str   => LexTokenManager.Null_String);
      else
         Both_Choice_Bounds_Known := True;
      end if;

      --# assert (STree.Syntax_Node_Type (First_Node, STree.Table) = SP_Symbols.simple_expression or
      --#           STree.Syntax_Node_Type (First_Node, STree.Table) = SP_Symbols.annotation_simple_expression) and
      --#   (STree.Syntax_Node_Type (Second_Node, STree.Table) = SP_Symbols.range_constraint or
      --#      STree.Syntax_Node_Type (Second_Node, STree.Table) = SP_Symbols.simple_expression or
      --#      STree.Syntax_Node_Type (Second_Node, STree.Table) = SP_Symbols.annotation_range_constraint or
      --#      STree.Syntax_Node_Type (Second_Node, STree.Table) = SP_Symbols.annotation_simple_expression or
      --#      Second_Node = STree.NullNode) and
      --#   not Semantic_Errors_Found and
      --#   ((Both_Choice_Bounds_Known and Is_A_Range) -> (Choice_Lower_Bound.Is_Defined and Choice_Upper_Bound.Is_Defined)) and
      --#   Aggregate_Stack.Stack_Is_Valid (Aggregate_Stack.State) and
      --#   ((Index_Type_Lower_Bound.Is_Defined and Index_Type_Upper_Bound.Is_Defined) ->
      --#      (Index_Type_Lower_Bound.Value <= Index_Type_Upper_Bound.Value)) and
      --#   (Complete_Rec.ActualUpperBound - Complete_Rec.LowerBound < ExaminerConstants.CompleteCheckSize) and
      --#   (Dictionary.Is_Null_Symbol (Index_Type_Symbol) or Dictionary.IsTypeMark (Index_Type_Symbol, Dictionary.Dict));

      if Both_Choice_Bounds_Known then
         -- check the case choice lies within controlling type
         if not Is_Choice_In_Range
           (Choice_Lower    => Choice_Lower_Bound,
            Choice_Upper    => Choice_Upper_Bound,
            Choice_Is_Range => Is_A_Range,
            Range_Lower     => Index_Type_Lower_Bound,
            Range_Upper     => Index_Type_Upper_Bound) then
            if Case_Choice_Sort = Range_Constraint then
               ErrorHandler.Semantic_Error
                 (Err_Num   => 410,
                  Reference => ErrorHandler.No_Reference,
                  Position  => STree.Node_Position (Node => Second_Node),
                  Id_Str    => LexTokenManager.Null_String);
            else
               ErrorHandler.Semantic_Error
                 (Err_Num   => 410,
                  Reference => ErrorHandler.No_Reference,
                  Position  => STree.Node_Position (Node => First_Node),
                  Id_Str    => LexTokenManager.Null_String);
            end if;
            Semantic_Errors_Found := True;
         elsif Is_A_Range and then Is_Range_Empty (Range_Lower => Choice_Lower_Bound,
                                                   Range_Upper => Choice_Upper_Bound) then
            if Case_Choice_Sort = Range_Constraint then
               ErrorHandler.Semantic_Error
                 (Err_Num   => 409,
                  Reference => ErrorHandler.No_Reference,
                  Position  => STree.Node_Position (Node => Second_Node),
                  Id_Str    => LexTokenManager.Null_String);
            else
               ErrorHandler.Semantic_Error
                 (Err_Num   => 409,
                  Reference => ErrorHandler.No_Reference,
                  Position  => STree.Node_Position (Node => First_Node),
                  Id_Str    => LexTokenManager.Null_String);
            end if;
            Semantic_Errors_Found := True;
         end if;

         --# assert (STree.Syntax_Node_Type (First_Node, STree.Table) = SP_Symbols.simple_expression or
         --#           STree.Syntax_Node_Type (First_Node, STree.Table) = SP_Symbols.annotation_simple_expression) and
         --#   (STree.Syntax_Node_Type (Second_Node, STree.Table) = SP_Symbols.range_constraint or
         --#      STree.Syntax_Node_Type (Second_Node, STree.Table) = SP_Symbols.simple_expression or
         --#      STree.Syntax_Node_Type (Second_Node, STree.Table) = SP_Symbols.annotation_range_constraint or
         --#      STree.Syntax_Node_Type (Second_Node, STree.Table) = SP_Symbols.annotation_simple_expression or
         --#      Second_Node = STree.NullNode) and
         --#   Both_Choice_Bounds_Known and
         --#   ((not Semantic_Errors_Found and Is_A_Range) -> (Choice_Lower_Bound.Value <= Choice_Upper_Bound.Value)) and
         --#   Aggregate_Stack.Stack_Is_Valid (Aggregate_Stack.State) and
         --#   ((Index_Type_Lower_Bound.Is_Defined and Index_Type_Upper_Bound.Is_Defined) ->
         --#      (Index_Type_Lower_Bound.Value <= Index_Type_Upper_Bound.Value)) and
         --#   (Complete_Rec.ActualUpperBound - Complete_Rec.LowerBound < ExaminerConstants.CompleteCheckSize) and
         --#   (Dictionary.Is_Null_Symbol (Index_Type_Symbol) or Dictionary.IsTypeMark (Index_Type_Symbol, Dictionary.Dict));

         -- check the case choice lies within Range_Constraint type
         if Case_Choice_Sort = Range_Constraint then
            Sem.Get_Type_Bounds
              (Type_Symbol => First_Result.Type_Symbol,
               Lower_Bound => Range_Constraint_Lower_Bound,
               Upper_Bound => Range_Constraint_Upper_Bound);

            if not Is_Choice_In_Range
              (Choice_Lower    => Choice_Lower_Bound,
               Choice_Upper    => Choice_Upper_Bound,
               Choice_Is_Range => Is_A_Range,
               Range_Lower     => Range_Constraint_Lower_Bound,
               Range_Upper     => Range_Constraint_Upper_Bound) then
               ErrorHandler.Semantic_Error
                 (Err_Num   => 413,
                  Reference => ErrorHandler.No_Reference,
                  Position  => STree.Node_Position (Node => Second_Node),
                  Id_Str    => LexTokenManager.Null_String);
               Semantic_Errors_Found := True;
            end if;
         end if;
      end if;
   end if;

   --# assert (STree.Syntax_Node_Type (First_Node, STree.Table) = SP_Symbols.simple_expression or
   --#           STree.Syntax_Node_Type (First_Node, STree.Table) = SP_Symbols.annotation_simple_expression) and
   --#   ((not Semantic_Errors_Found and Both_Choice_Bounds_Known and Is_A_Range) ->
   --#      (Choice_Lower_Bound.Value <= Choice_Upper_Bound.Value)) and
   --#   Aggregate_Stack.Stack_Is_Valid (Aggregate_Stack.State) and
   --#   ((Index_Type_Lower_Bound.Is_Defined and Index_Type_Upper_Bound.Is_Defined) ->
   --#      (Index_Type_Lower_Bound.Value <= Index_Type_Upper_Bound.Value)) and
   --#   (Complete_Rec.ActualUpperBound - Complete_Rec.LowerBound < ExaminerConstants.CompleteCheckSize) and
   --#   (Dictionary.Is_Null_Symbol (Index_Type_Symbol) or Dictionary.IsTypeMark (Index_Type_Symbol, Dictionary.Dict));

   if (not Semantic_Errors_Found)
     and then Both_Choice_Bounds_Known
     and then (Aggregate_Flags.Check_Completeness or else Aggregate_Flags.Check_Overlap) then
      if Is_A_Range then
         CompleteCheck.SeenRange
           (Complete_Rec,
            Choice_Lower_Bound.Value,
            Choice_Upper_Bound.Value,
            Out_Of_Range_Seen,
            Overlap_Seen);
      else
         CompleteCheck.SeenElement (Complete_Rec, Choice_Lower_Bound.Value, Out_Of_Range_Seen, Overlap_Seen);
      end if;
      if Out_Of_Range_Seen then
         Aggregate_Flags.Out_Of_Range_Seen := True;
      end if;
      if Aggregate_Flags.Check_Overlap and then Overlap_Seen = CompleteCheck.Overlap then
         ErrorHandler.Semantic_Error
           (Err_Num   => 407,
            Reference => ErrorHandler.No_Reference,
            Position  => STree.Node_Position (Node => First_Node),
            Id_Str    => LexTokenManager.Null_String);
         Semantic_Errors_Found := True;
      end if;
   end if;

   --# assert Aggregate_Stack.Stack_Is_Valid (Aggregate_Stack.State) and
   --#   ((Index_Type_Lower_Bound.Is_Defined and Index_Type_Upper_Bound.Is_Defined) ->
   --#      (Index_Type_Lower_Bound.Value <= Index_Type_Upper_Bound.Value)) and
   --#   (Complete_Rec.ActualUpperBound - Complete_Rec.LowerBound < ExaminerConstants.CompleteCheckSize) and
   --#   (Dictionary.Is_Null_Symbol (Index_Type_Symbol) or Dictionary.IsTypeMark (Index_Type_Symbol, Dictionary.Dict));

   if Semantic_Errors_Found then
      Aggregate_Flags.Check_Completeness := False;
   end if;

   Aggregate_Stack.Push
     (Type_Sym     => Index_Type_Symbol,
      Lower_Bound  => Index_Type_Lower_Bound,
      Upper_Bound  => Index_Type_Upper_Bound,
      Agg_Flags    => Aggregate_Flags,
      Counter      => Entry_Counter,
      Complete_Rec => Complete_Rec);
end Wf_Aggregate_Choice;
