--  { dg-do run }

procedure Array33 is
  generic
    type Item_T is private; -- The type of which the interval is made of.
    type Bound_T is private;
    None_Bound : Bound_T;
    Bounds_Are_Static : Boolean := False;
    type Value_T is private;
    type Base_Index_T is range <>;
  package General_Interval_Partition_G is
    subtype Length_T is Base_Index_T range 0 .. Base_Index_T'Last;
    subtype Index_T  is Base_Index_T range 1 .. Base_Index_T'Last;
    type T is private;
    function Single (First, Last : Bound_T; Value : Value_T) return T;
    function Single1 (First, Last : Bound_T; Value : Value_T) return T;
  private
    type Bounds_Array_T is array (Length_T range <>) of Bound_T;
    type Values_Array_T is array (Index_T  range <>) of Value_T;

    First_Bounds_Index : constant Length_T
        := 2 * Boolean'Pos (Bounds_Are_Static);
    -- See below explanation on indexing the bounds.


    type Obj_T (Length : Length_T) is
      record
        Bounds : Bounds_Array_T (First_Bounds_Index .. Length)
           := (others => None_Bound);
        -- This is tricky. If Bounds_Are_Static is true, the array does not
        --  store the lower or upper bound.
        -- This lowers memory requirements for the data structure at the cost
        --  of slightly more complex indexing.
        --
        -- Bounds as seen internally depending on the parameter:
        --
        -- Bounds_Are_Static | Lower_Bound | Inbetween Bounds (if any) | Upper_Bound
        --     True         => Max_First   & Bounds (2 .. Length)      & Min_Last
        --     False        => Bounds (0)  & Bounds (1 .. Length - 1)  & Bounds (Length)
        --
        Values : Values_Array_T (1 .. Length);
      end record;

    type T is access Obj_T;
    --@@ if ccf:defined(debug_pool) then
    --@@! for T'Storage_Pool use Pool_Selection_T'Storage_Pool;
    --@@ end if

  end General_Interval_Partition_G;

  package body General_Interval_Partition_G is

    function Single (First, Last : Bound_T; Value : Value_T) return T is
    begin
      return new Obj_T'(Length => 1,
                        Bounds => (if Bounds_Are_Static
                                   then (2 .. 0 => None_Bound) 
                --  Now raises constraint error here
                                   else (0 => First, 1 => Last)),
                        Values => (1 => Value));
    end Single;
    function Single1 (First, Last : Bound_T; Value : Value_T) return T is
    begin
      return new Obj_T'( 1,
                         (if Bounds_Are_Static
                                   then (2 .. 0 => None_Bound) 
                --  Now raises constraint error here
                                   else (0 => First, 1 => Last)),
                        (1 => Value));
    end Single1;
  end General_Interval_Partition_G;

  type T is new Integer;

  package Partition is new General_Interval_Partition_G (Item_T            => T,
                                                         Bound_T           => T,
                                                         None_Bound        => 0,
                                                         Bounds_Are_Static => True,
                                                         Value_T           => T,
                                                         Base_Index_T      => Natural);
  X : constant Partition.T := Partition.Single (1,1,1);
  Z : constant Partition.T := Partition.Single1 (1,1,1);
begin
  null;
end;