Type Tests

General discussions about working with the Astrobe IDE and programming the Raspberry Pi RP2040 and the Pi Pico board.
Post Reply
gray
Posts: 175
Joined: Tue Feb 12, 2019 2:59 am
Location: Mauritius

Type Tests

Post by gray » Sat Jul 19, 2025 11:38 am

Consider this first test case:

Code: Select all

MODULE M0;

  IMPORT Main, Out;

  TYPE
    Mp* = POINTER TO Mdesc;
    M0p* = POINTER TO M0desc;
    Mdesc* = RECORD END;
    M0desc* = RECORD (Mdesc) END;
    
    M1p* = POINTER TO M1desc;
    M1desc* = RECORD (M0desc) END;

  VAR
    mp: Mp;
    m0p: M0p;
    m1p: M1p;

BEGIN
  NEW(m1p);
  mp := m1p;
  ASSERT(mp IS M0p, 200);
  Out.String("assert ok"); Out.Ln;
  m0p := mp(M0p);
  Out.String("type guard ok"); Out.Ln
END M0.
As expected, the program runs with both the ASSERT as well as the type guard passing.

Now consider this modified second test case, moving part of the type defs to another module:

Code: Select all

MODULE T2;
  TYPE
    Mp* = POINTER TO Mdesc;
    M0p* = POINTER TO M0desc;
    Mdesc* = RECORD END;
    M0desc* = RECORD (Mdesc) END;
END T2.

MODULE M1;

  IMPORT T2, Main, Out;

  TYPE
    M1p* = POINTER TO M1desc;
    M1desc* = RECORD (T2.M0desc) END;

  VAR
    mp: T2.Mp;
    m0p: T2.M0p;
    m1p: M1p;

BEGIN
  NEW(m1p);
  mp := m1p;
  ASSERT(mp IS T2.M0p, 200);
  Out.String("assert ok"); Out.Ln;
  m0p := mp(T2.M0p);
  Out.String("type guard ok"); Out.Ln
END M1.
Now the ASSERT fails, and when commenting the ASSERT out, so does the type guard.

What do I miss?

(Latest Astrobe for RP2350, command line compiler and linker.)

gray
Posts: 175
Joined: Tue Feb 12, 2019 2:59 am
Location: Mauritius

Re: Type Tests

Post by gray » Sun Jul 20, 2025 1:12 pm

Analysis attempt.

First case, with M0, ie. with all type defs in the module, we have this binary representation of the types (from the linked assembly listing, ie. with resolved addresses):

Code: Select all

MODULE M0;
  TYPE
    Mp* = POINTER TO Mdesc;
    M0p* = POINTER TO M0desc;
    Mdesc* = RECORD END;
.     4  010004988H      00000H  <Type:   0>
.     8  01000498CH      00000H  <Type:   0>
.    12  010004990H      00000H  <Type:   0>
.    16  010004994H      00000H  <Type:   0>
.    20  010004998H      00000H  <Type:   0>
    M0desc* = RECORD (Mdesc) END;
.    24  01000499CH      00000H  <Type:   0>
.    28  0100049A0H  01000499CH  <Type:   0180000H>
.    32  0100049A4H      00000H  <Type:   0>
.    36  0100049A8H      00000H  <Type:   0>
.    40  0100049ACH      00000H  <Type:   0>
    M1p* = POINTER TO M1desc;
    M1desc* = RECORD (M0desc) END;
.    44  0100049B0H      00000H  <Type:   0>
.    48  0100049B4H  01000499CH  <Type:   018000EH>
.    52  0100049B8H  0100049B0H  <Type:   02C0018H>
.    56  0100049BCH      00000H  <Type:   0>
.    60  0100049C0H      00000H  <Type:   0>
The values at the respective extension levels are addresses of the corresponding type records (to self or parent), which are used for the type check:

Code: Select all

  (* .. *)
  ASSERT(mp IS M0p, 200);
.   168  010004A2CH  0F8DF0094H  ldr.w     r0,[pc,#148] -> 320
.   172  010004A30H      06800H  ldr       r0,[r0] <= get address value in mp (is POINTER TO M1desc)
.   174  010004A32H  0F8501C04H  ldr.w     r1,[r0,#-4] <= get address of M1desc type record from heap
.   178  010004A36H      06849H  ldr       r1,[r1,#4] <= get value ext. level 1 of M1desc record (address of M0desc)
.   180  010004A38H      0467BH  mov       r3,pc
.   182  010004A3AH  0F1B302A0H  subs.w    r2,r3,#160 <= get address of M0desc record
.   186  010004A3EH      04291H  cmp       r1,r2 <= compare addresses
.   188  010004A40H      0D001H  beq.n     2 -> 194
.   190  010004A42H      0DFC8H  svc       200
    (* .. *)
.   320  010004AC4H  02003FD88H  <Global: M0 data> <= mp
Second case, with T2 and M1:

Code: Select all

MODULE T2;
  TYPE
    Mp* = POINTER TO Mdesc;
    M0p* = POINTER TO M0desc;
    Mdesc* = RECORD END;
.     4  010004958H      00000H  <Type:   0>
.     8  01000495CH      00000H  <Type:   0>
.    12  010004960H      00000H  <Type:   0>
.    16  010004964H      00000H  <Type:   0>
.    20  010004968H      00000H  <Type:   0>
    M0desc* = RECORD (Mdesc) END;
.    24  01000496CH      00000H  <Type:   0>
.    28  010004970H  01000496CH  <Type:   0180000H>
.    32  010004974H      00000H  <Type:   0>
.    36  010004978H      00000H  <Type:   0>
.    40  01000497CH      00000H  <Type:   0>

MODULE M1;
  TYPE
    M1p* = POINTER TO M1desc;
    M1desc* = RECORD (M0desc) END;
.     4  010004988H      00000H  <Type:   0>
.     8  01000498CH  02003FD74H  <Type:   020000H> <= here (see below)
.    12  010004990H  010004988H  <Type:   040000H>
.    16  010004994H      00000H  <Type:   0>
.    20  010004998H      00000H  <Type:   0>
Same code section as above:

Code: Select all

  ASSERT(mp IS M0p, 200);
.   128  010004A04H  0F8DF0090H  ldr.w     r0,[pc,#144] -> 276
.   132  010004A08H      06800H  ldr       r0,[r0]
.   134  010004A0AH  0F8501C04H  ldr.w     r1,[r0,#-4]
.   138  010004A0EH      06849H  ldr       r1,[r1,#4]
.   140  010004A10H  0F8DF2078H  ldr.w     r2,[pc,#120] -> 264
.   144  010004A14H      04291H  cmp       r1,r2
.   146  010004A16H      0D001H  beq.n     2 -> 152
.   148  010004A18H      0DFC8H  svc       200
    (* .. *)
.   264  010004A8CH  01000496CH  <Global: T2 code>
.   276  010004A98H  02003FD88H  <Global: M2 data>
At relative address 8 in M1 we have a RAM address (02003FD74H) at extension level 1 of M1desc (it's an address in the stack range in this case, inital stack pointer is 2003FD78H), which gets compared to the address of M0desc in T2 code space (01000496CH). That is, it appears that address in M1desc does not get resolved correctly. Then again, my understanding and analysis can well be wrong.

gray
Posts: 175
Joined: Tue Feb 12, 2019 2:59 am
Location: Mauritius

Re: Type Tests

Post by gray » Sun Jul 27, 2025 9:30 am


Post Reply