Expect ancestor type of

I struggle with extension aggregates with limited types. I thought I understood the syntax but it seems not:

function  Percent_cell
    (Sheet : in out Spreadsheet_type'Class; Value : String)
    return Percent_cell_type'Class is
    ((Formula_Cell (Sheet, Value) with null record))

The last line causes this error:

je-spreadsheets.adb:26:31: error: expect ancestor type of “Percent_cell_type’CLASS”

The fomula_cell function returns an element of Formula_cell_type, which is the direct ancestor of Percent_cell_type. What do I do ?

I can’t reproduce your specific error with the code provided but try to qualify your return type and see if that helps (note the apostrophe for type qualification rather than type conversion):

function  Percent_cell
        (Sheet : in out Spreadsheet_type'Class; 
         Value : String)
         return Percent_cell_type'Class is
    (Percent_cell_type'(Formula_Cell (Sheet, Value) with null record));

Okay, so I think I understood the issue.
You can’t change a discriminant of an expression in a delta aggregate, and you can’t provide one (or all) in the ancestral part of an extension aggregate either ! Meaning I can’t do anything with them. Or did I miss something ?
This fails:

pragma Ada_2022;
with Ada.Text_IO;
use Ada.Text_IO;

package test is
   type SType is tagged null record;
   type FC_type (Sheet: access Stype'Class) is tagged null record;
   type BFC_type (Sheet: access stype'Class) is new fc_type (Sheet) with null record;
   package Constructor is
      function  FC (Sheet : in out Stype'Class;
                    Value : String) return FC_type is (Seet => Sheet'Access);
       function  BFC (Sheet : in out Stype'Class; Value : String) return BFC_type is
	      	(FC (Sheet, Value) with null record); -- HERE
	end Constructor;
end test;

I don’t understand the reason. I thought both delta and extension aggregates worked like a macro expansion, taking the original expression and changing fields ?
When limited types are involved it is not considered copying, and I don’t think a tagged type can be derived without its full definition at least in the private part. As for unknown discriminant, here a value is given through a function.

So why the limitation ?

I don’t know offhand how to fix the expression function version, but if you are ok using a full function body (so you’ll need an adb file for your package), then you can try to qualify it using subtypes to tell the compiler exactly what you expect:

    package test is
    	type Spreadsheet_Type is abstract tagged limited null record;
    	type Spreadsheet_access is access all Spreadsheet_type'Class;
    	type Cell_Type (Sheet : Spreadsheet_Access) is abstract tagged limited null record;
    	type Formula_Cell_Type (Sheet : Spreadsheet_Access) is new Cell_Type(Sheet) with null record;
    	type Based_Formula_Cell_Type (Sheet : Spreadsheet_Access; Base: Ada.Text_IO.Number_Base) 
    	    is new Formula_Cell_Type (Sheet) with null record;
    	package Constr is
    	
    		function  Formula_Cell 
    		    (Sheet : in out Spreadsheet_type'Class) 
    		     return Formula_cell_type 
    		is (Cell_type with Sheet'Unchecked_Access);
    		
    		function  Based_Formula_Cell 
    		    (Sheet : in out Spreadsheet_type'Class;                       
    		     Value : String; Base: Ada.Text_IO.Number_Base) 
    		     return Based_Formula_Cell_Type;
        end CONSTR;
    end test;
    
    package body test is
        package body constr is
            function  Based_Formula_Cell 
    		    (Sheet : in out Spreadsheet_type'Class;                       
    		     Value : String; Base: Ada.Text_IO.Number_Base) 
    		     return Based_Formula_Cell_Type 
    		is 
                -- setup a subtype to qualify the function result
    		    subtype Parent is Formula_Cell_Type(Sheet'Unchecked_Access);
    		begin
    		    return (Parent'(Formula_cell(Sheet)) 
    		        with Sheet => Sheet'Unchecked_Access,
                         Base  => Base);
            end Based_Formula_Cell;
        end constr;
    end test;

I haven’t tested passed getting it to compile in jdoodle, but something to explore?

ref: Online Compiler and Editor/IDE for Java, C, C++, PHP, Python, Ruby, Perl - Code and Run Online