adaspark-ada

Ada constraint error: Discriminant check failed. What does this mean?


I've tried searching the docs and the code, but I'm unable to find what this is and therefore how to correct it.

Scenario:

I'm using the Ada SPARK vectors library and I have the following code:

package MyPackage
  with SPARK_Mode => On
is
  package New_Vectors is new Formal_Vectors (Index_Type => test, Element_Type => My_Element.Object);
type Object is private;
private

   type Object is
      record
         Data : New_Vectors.Vector (Block_Vectors.Last_Count);
         Identifier : Identifier_Range;
      end record;


I get the error when the code calls:

function Make (Identifier : Identifier_Range) return Object is
   begin
      return (
              Data => New_Vectors.Empty_Vector,
              Identifier => Identifier);
   end Make;

Pointing to Empty_Vector. The difficulty is that Empty_Vector defines the Capacity as 0 which appears to be leading to the problem. Now I'm not sure then how to deal with that as Capacity seems to be in the type definition (having looked in a-cofove.ads).

So basically I'm stuck as to how to resolve this; or quite how to spot this happening in future.


Solution

  • Your analysis is correct. The error occurs because you attempt to assign an empty vector (i.e. a vector with capacity 0) to a vector with capacity Block_Vectors.Last_Count (which appears to be non-zero).

    You actually do not need to initialize the vector explicitly in order to use it. A default initialization (using <>, see, for example, here) suffices as shown in de example below.

    However, in order to prove the absence of runtime errors, you do need to explicitly clear the vector using Clear. The Empty_Vector function can then be used to in assertions that check if a vector is empty or not as shown in the example below. The example can be shown to be free of runtime errors using gnatprove. For example by opening the prove settings via menu SPARK > Prove in GNAT Studio, selecting "Report checks moved" in the "General" section (top left) and then running the analysis by selecting "Execute" (bottom right).

    main.adb

    with Ada.Text_IO; use Ada.Text_IO;
    with Ada.Containers.Formal_Vectors;
    
    procedure Main with SPARK_Mode is
          
       package My_Vectors is new Ada.Containers.Formal_Vectors 
         (Index_Type   => Natural, 
          Element_Type => Integer);
       use My_Vectors;
       
       type Object is record
          Data  : Vector (Capacity => 10);   --  Max. # of elements: 10
          Value : Integer;
       end record;
       
       --  Initialize with default value (i.e. <>), no explicit initialization needed.
       Obj : Object :=
         (Data  => <>,
          Value => 42);
       
    begin
       
       --  Clear the vector, required for the assertions to be proven.
       Clear (Obj.Data);
             
       --  Assert that the vector is not empty.
       pragma Assert (Obj.Data = Empty_Vector);
          
       --  Populate the vector with some elements.
       Append (Obj.Data, 4);
       Append (Obj.Data, 5);
       Append (Obj.Data, 6);
       
       --  Assert that the vector is populated.
       pragma Assert (Obj.Data /= Empty_Vector);
          
       --  Show the contents of Obj.Data.
       Put_Line ("Contents of Obj.Data:");
       for I in Natural range 0 .. Natural (Length (Obj.Data)) - 1 loop
          Put_Line ("[" & I'Image & "]" & Element (Obj.Data, I)'Image);
       end loop;
       New_Line;
       
       --  or, alternatively using an iterator ...   
       declare
          I : Extended_Index := Iter_First (Obj.Data);
       begin
          while Iter_Has_Element (Obj.Data, I) loop
             Put_Line ("[" & I'Image & "]" & Element (Obj.Data, I)'Image);
             I := Iter_Next (Obj.Data, I);
          end loop;
       end;
       New_Line;
       
       --  Show the contents of Obj.Value.
       Put_Line ("Contents of Obj.Value:");
       Put_Line (Obj.Value'Image);
       New_Line;   
       
    end Main;
    

    output

    Contents of Obj.Data:
    [ 0] 4
    [ 1] 5
    [ 2] 6
    
    [ 0] 4
    [ 1] 5
    [ 2] 6
    
    Contents of Obj.Value:
     42