Remark: The compiler decides on the type of an integer constant
based on the value: An integer constant gets the smallest possible
signed type.
...
constants in range 128..255 are mapped to byte, etc.
...
These two statements contradict each other, am I wrong?
I fail to see how these two statements could contradict. If you still think the same after reading this post then please feel free to elaborate to make me better understand.
That means constants in the range -128..127 are mapped to shortint,
constants in range 128..255 are mapped to byte, etc.
64 = shortint
128 = byte
192 = byte
The results from the posted program confirms that the resulted answers are 1 byte in size, except when the not operator comes into play.
Take the following program that also shows the bit representation of the resulted values
begin
WriteLn;
WriteLn(64);
WriteLn(SizeOf(64));
WriteLn(BinStr(64, SizeOf(64) * 8));
WriteLn;
WriteLn(128);
WriteLn(SizeOf(128));
WriteLn(BinStr(128, SizeOf(128) * 8));
WriteLn;
WriteLn(128 or 64);
WriteLn(SizeOf(128 or 64));
WriteLn(BinStr(128 or 64, SizeOf(128 or 64) * 8));
WriteLn;
WriteLn(not(128 or 64));
WriteLn(SizeOf(not(128 or 64)));
WriteLn(BinStr(not(128 or 64), SizeOf(not(128 or 64)) * 8));
end.
which shows:
64
1
01000000
128
1
10000000
192
1
11000000
-193
8
1111111111111111111111111111111111111111111111111111111100111111
Now, I do not claim to know/understand how this is actually implemented in the compiler (haven't looked) but if I would have to take a guess then I assume (and that assumption might very well be wrong) that when the actual negation takes place that the negative flag (of the cpu) is set and that should be reflected in the result.
Because the highest bit is already set in byte value 192 (sign bit) the result is or needs to be expanded.
The same documentation that was quoted states that in that case result does not fit in the two explained ranges and that in such case it is expanded to a 64 integer.
That also seems to be confirmed by the resulted output.
fwiw: one could also opt for implementing a self written custom bye/word/dword type that is more in line with what is expected (such as how an assembler/cpu does things, and i assume OP expected the not operator to work). You could then also use your own custom operators for such a custom type and implement these operators to act/behave any which way you see fit. Even though the compiler does warn you explicitly when things are not going according to plan when using casting, but in that case simply ignoring the warnings might result in unexpected results/behaviour on the long run.
edit: typo's/rewording