Consider the following declarations:
type My_Type is range 1 .. 3;
type My_Array is array (My_Type) of Float;
type Your_Array is array (My_Type range <>) of Float;
MA : My_Array; -- Definite type, no bounds required
YAB : Your_Array (1 .. 2); -- Indefinite type, explicit bounds
YAU : Your_Array := (1.1, 2.2, 3.3); -- No explicit bounds but will be 1 .. 3
Now, suppose we want to iterate over all different ranges of the above types and objects like so:
for I in My_Type'Range loop
case I is
when 1 => null;
when 2 => null;
when 3 => null;
end case;
end loop;
for I in MA'Range loop
case I is
when 1 => null;
when 2 => null;
when 3 => null;
end case;
end loop;
for I in YAB'Range loop
case I is
when 1 => null;
when 2 => null;
end case;
end loop;
The compiler can very nicely determine all possible ranges and statically confirm that all possible alternatives in the case
statements have been covered.
However, trying to do the same with the last object where the bounds are determined from the assignment i.e. :
for I in YAU'Range loop
case I is
when 1 => null;
when 2 => null;
when 3 => null;
end case;
end loop;
results in the error:
So, in this case I
is clearly taken to be a signed byte which is the base type that the compiler has chosen for My_Type
and hence it complains that the rest of the alternatives aren’t covered in the case
.
The solution is to add a when others => ..
like so:
for I in YAU'Range loop
case I is
when 1 => null;
when 2 => null;
when 3 => null;
when others => raise Constraint_Error with "Impossible!";
end case;
end loop;
But this others
case can never be, right? Isn’t it a bit odd that the compiler can pick the bounds up in all other cases but in this last case it fails to do that and it falls-back to the base type range?
What’s even more interesting is that doing something like:
YAU : Your_Array := (1.1, 2.2, 3.3, 4.4);
results in the warning:
so clearly, the compiler is able to determine the bounds statically in the bounds-from-assignment case..
(The same behaviour occurs in the case where YAU
would be passed as an argument to a subprogram i.e. maybe declared to take YA : Your_Array
)
The somewhat inconvenient issue here might be the fact that a fabricated when others => ..
alternative needs to be added which slightly breaks the nice static case
alternatives coverage and perhaps lowers the confidence to someone reading this code.
Any thoughts? (using gnat_native=14.2.1
)