Discrimnant check failed in absence of constraints

Read the second. This is more on point.

In the following implementation of a linked list, how can we get “discriminant check failed” for the current.all assignment statement inside the loop. But Block is mutable and I always do whole assignments so I don’t understand.
The idea was to create the last piece first, whose length is between 1 and the chosen chunk size, and if that wasn’t the whole string, insert the rest of the links from the start of the string. The “hoops” and “remainder” variable’s valuess are correct. I must be missing something.

pragma Ada_2022;
pragma extensions_allowed (all);
with Ada.Text_IO; use Ada.Text_IO;
procedure Test is

size_chunk : constant := 10;
	subtype Limit is Natural range 0..size_chunk;
	type Block (Length: Limit := size_chunk) is record
		Value: String (1..Length);
		Next: access Block;
	end record;
	type Vstring is record
		First: access Block;
		Length: Natural := 0;
	end record;
	function Create (Str : String) return Vstring is
		remainder : constant String := Str(Str'Last + 1 - (Str'Length mod size_chunk) .. Str'Last);
		Hoops : constant Natural := Str'Length / size_chunk;
		is_null : constant Boolean := Str'Length = 0; 
		Vstr : Vstring := (if is_null then (null,0)
			else 	(new Block'(remainder'Length, remainder, null), Str'Length));
		current : access Block := Vstr.first;
	begin
		for I in 1..Hoops loop
			current.all := (size_chunk, Str(Str'First + (I - 1) * size_chunk  .. Str'First + I * size_chunk - 1), @); -- HHHHHHHEEEEERE
			current := current.next;
		end loop;
		return Vstr;
	end Create;

A: Vstring := create ("AAAAAAAAAAAAAAAAAAA");

begin 
null;
end;

I thought in the HHHEEERRREEE line it should end with @'Access, but that gives error: access-to-variable designates constant.

Using ’Unrestricted_Access (best avoided if possible, but in the interests of exploring the problem…), it turns out that Current’Length is 9 for I = 1, so writing size_chunk to it will violate the discriminant check.

Ahhh I finally did it. Now that’s elegance. No needless allocation, no special case failure.
I hate indirections and pointers, this is nearly impossible to get your head around.

function Create (Str : String) return Vstring is
	remainder : constant String := Str(Str'Last + 1 - (Str'Length mod size_chunk) .. Str'Last);
begin
	return (null, 0) when Str'Length = 0;
	declare
		Vstr : Vstring := (new Block'(remainder'Length, remainder, null), Str'Length);
		temp: aliased Block := (0,"",null); 
		first, current : access Block := temp'Access;
	begin
		for I in 1..(Str'Length - remainder'Length) / size_chunk loop
			current.next := new Block'(size_chunk, Str(Str'First + (I - 1) * size_chunk  .. Str'First + I * size_chunk - 1), null);
			current := current.next;
		end loop;
		current.next := new Block'(remainder'Length, remainder, null);
		vstr.first := first.next;
		return Vstr;
	end;
end Create;

as for the above, first thing it seems that because @ is a constant view of the target you must use access to constant types even if if nothing is assignated during that statement. I wonder if this rule could be changed, since what it points to isn’t necessarily a constant.

I don’t understand what fails though.
at first iteration, lower bound of the substring is 1, upper is 10. it still causes “length check failed”.
replace the loop with

for I in 1..Hoops loop
	put_line("length = " & Integer'Image (Str'First + (I - 1) * size_chunk - Str'First + I * size_chunk - 1));
	put_line("size_chunk = " & Integer'Image (size_chunk));
	put_line("bottom = " & Integer'Image (Str'First + (I - 1) * size_chunk));
	put_line("top = " & Integer'Image (Str'First + I * size_chunk - 1));
	current.all := (size_chunk - 1, Str(Str'First + (I - 1) * size_chunk  .. Str'First + I * size_chunk - 1), @'Unrestricted_Access); -- HHHHHHHEEEEERE
	current := current.next;
end loop;

How is this length calculation even done ? It should be top-bottom + 1, no ?