Incorrect Handling of Pointer Type Base and Incompatible Assignment
geekstakulus opened this issue · comments
Introduction
In Oberon-07, two pointer types are considered equal if they have the same base type. Consequently, if a record field is declared as a pointer to a specific type, and later another type is declared as a pointer to the same base type, both types should be equal and assignment compatible.
Current Behavior
Consider the following code snippet:
MODULE PointerCompat;
TYPE
Rec = RECORD
x, y : INTEGER;
END;
PRec1 = POINTER TO Rec;
PRec2 = POINTER TO Rec;
VAR
p1 : PRec1;
p2 : PRec2;
BEGIN
NEW(p1);
p2 := p1;
p2.x := 12;
p2.y := 10;
ASSERT(p1 = p2);
ASSERT(p1.x = p2.x);
ASSERT(p1.y = p2.y)
END PointerCompat.
In this example, PRec1
and PRec2
are equal types and assignment compatible, which is expected behavior.
However, when declaring a record with a field of type POINTER TO Rec
and subsequently attempting to assign it to a variable declared as POINTER TO Rec
, as shown below:
MODULE PointerCompat2;
IMPORT Out;
TYPE
Rec = RECORD
x, y : INTEGER;
next : POINTER TO Rec
END;
PRec1 = POINTER TO Rec;
PRec2 = POINTER TO Rec;
VAR
p1 : PRec1;
p2 : PRec2;
p : PRec1;
BEGIN
NEW(p1);
NEW(p2);
p1.x := 13;
p1.y := 19;
p1.next := p2;
p2.x := 12;
p2.y := 10;
p := p1;
WHILE p # NIL DO
Out.String("x = "); Out.Int(p.x, 0); Out.Ln;
Out.String("y = "); Out.Int(p.y, 0); Out.Ln;
p := p.next
END
END PointerCompat2.
The compiler reports the following errors:
PointerCompat2.Mod:16:0: undefined pointer base: END
PointerCompat2.Mod:21:16: illegal assignment
PointerCompat2.Mod:30:0: illegal assignment
PointerCompat2.Mod:31:19: compilation FAILED
The compiler does not recognize the pointer base of PRec1
declared as the type of variable p
. Consequently, it does not recognize the assignment of a variable of type POINTER TO Rec
, which is the same as the one defined for the field next
of Rec
.
The issue is resolved when the field next
is defined with a pre-declared pointer type, as demonstrated in the following code:
MODULE PointerCompat3;
IMPORT Out;
TYPE
PRec1 = POINTER TO Rec;
PRec2 = POINTER TO Rec;
Rec = RECORD
x, y : INTEGER;
next : PRec1
END;
VAR
p1 : PRec1;
p2 : PRec2;
p : PRec1;
BEGIN
NEW(p1);
NEW(p2);
p1.x := 13;
p1.y := 19;
p1.next := p2;
p2.x := 12;
p2.y := 10;
p := p1;
WHILE p # NIL DO
Out.String("x = "); Out.Int(p.x, 0); Out.Ln;
Out.String("y = "); Out.Int(p.y, 0); Out.Ln;
p := p.next
END
END PointerCompat3.
Expected Behavior
The compiler should successfully compile the code, regardless of whether record fields are declared with a pre-declared pointer type or directly as a pointer to the same type.
Repro Steps
- To observe this behavior:
- Compile the code in the three examples using the Oberonc compiler.
- Note that the compiler successfully compiles the code for
PointerCompat.Mod
andPointerCompat3.Mod
, but reports errors forPointerCompat2.Mod
.
Other Information
This issue has not been tested with the original compiler. However, when compiled with OBNC
, it does not present this problem and behaves as expected.
It looks like the scanner is out of sync, indeed the error points to keyword END
and the compiler assumes it is a type.
Thanks for reporting this, I'll push a fix soon.
OK, take your time. It isn't something urgent, but it is good that I caught it. There is no better way to catch bugs in a compiler than to write pretty bad code. LoL
Fixed.
Thanks again for the great bug reports! I really appreciate it!
Thanks for the quick fix! As usual, you are always fast at fixing bugs.
All working!