Recent

Author Topic: Incosistent compiler hint  (Read 3298 times)

Zoran

  • Hero Member
  • *****
  • Posts: 1745
    • http://wiki.lazarus.freepascal.org/User:Zoran
Incosistent compiler hint
« on: February 11, 2016, 04:13:08 pm »
FPC 3.0

This code:
Code: Pascal  [Select][+][-]
  1. function TestHint(N: LongInt): Boolean;
  2. begin
  3.   Result := (N mod 5) in [1, 2, 3];
  4. end;
  5.  
Gives this compiler hint:
Quote
Hint: The left operand of the IN operator should be byte sized

However, this code:
Code: Pascal  [Select][+][-]
  1. function TestHint(N: LongInt): Boolean;
  2. begin
  3.   Result := N in [1, 2, 3];
  4. end;
  5.  
does not give the hint!

I found (here) the explanation of this hint:
Quote
Hint: The left operand of the IN operator should be byte sized
    The left operand of the in operator is not an ordinal or enumeration which fits within 8 bits. This may lead to range check errors. The in operator currently only supports a left operand which fits within a byte. In the case of enumerations, the size of an element of an enumeration can be controlled with the {$PACKENUM} or {$Zn} switches.

Okay, but in both examples, left operand is LongInt, isn't it? The difference is that in first example (N mod 5) is used, and in the second N. N is of type LongInt, so 4-byte sized, what is the reason that compiler does not give hint?

howardpc

  • Hero Member
  • *****
  • Posts: 3998
Re: Incosistent compiler hint
« Reply #1 on: February 11, 2016, 04:32:39 pm »
In the second case, presumably the compiler converts the longint N to a byte for you (so it is compatible with the "in" set operator), since Pascal set elements must be byte-sized or less. So you have a behind-your-back  truncation of N's value. I'm not sure if this is intelligence built in to the compiler, or just luck that using the truncated N gives a correct result (since if N is larger than a byte value it cannot by definition be part of a Pascal set, so will never be "in" it in that case).

In the first case, the compiler has to allow N mod 5 to be a longint, since for most values of N the expression would be a longint. So it issues the valid warning.

Zoran

  • Hero Member
  • *****
  • Posts: 1745
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Incosistent compiler hint
« Reply #2 on: February 11, 2016, 04:46:59 pm »
In the second case, presumably the compiler converts the longint N to a byte for you (so it is compatible with the "in" set operator), since Pascal set elements must be byte-sized or less. So you have a behind-your-back  truncation of N's value. I'm not sure if this is intelligence built in to the compiler, or just luck that using the truncated N gives a correct result (since if N is larger than a byte value it cannot by definition be part of a Pascal set, so will never be "in" it in that case).

In the first case, the compiler has to allow N mod 5 to be a longint, since for most values of N the expression would be a longint. So it issues the valid warning.

I would expect this hint to warn me that N is a LongInt, since this function can accept any LongInt parameter. Your explanation is probably right, but I doubt it is intentional behaviour. I'm not sure if I should report this in bugtracker.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8436
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Incosistent compiler hint
« Reply #3 on: February 11, 2016, 05:35:46 pm »
Probably a wrong semantic check by the compiler. I experiment with some casts:
Code: Pascal  [Select][+][-]
  1. (N mod 5) in [1, 2, 3];         // hint
  2. SmallInt(N mod 5) in [1, 2, 3]; // no hint
  3. Word(N mod 5) in [1, 2, 3];     // no hint
  4. LongInt(N mod 5) in [1, 2, 3];  // no hint
  5. LongWord(N mod 5) in [1, 2, 3]; // no hint
  6. Int64(N mod 5) in [1, 2, 3];    // hint
  7. QWord(N mod 5) in [1, 2, 3];    // hint
  8.  
I don't remember where I read, but FPC always calculates in Int64, hence the uncasted expression seems to be regarded as Int64. The funny part is that neither of SmallInt, Word, LongInt nor LongWord are Byte size type, but no hint whatsoever.

Zoran

  • Hero Member
  • *****
  • Posts: 1745
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Incosistent compiler hint
« Reply #4 on: February 11, 2016, 05:36:02 pm »
In the second case, presumably the compiler converts the longint N to a byte for you (so it is compatible with the "in" set operator),

But... Interestingly, the two functions in my next example give different results (so, it seems that the implicit conversion does not happen):
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   sysutils;
  7.  
  8. function TestHint1(N: LongInt): Boolean;
  9. begin
  10.   Result := N in [1, 2, 3];
  11. end;
  12.  
  13. function TestHint2(N: LongInt): Boolean;
  14. begin
  15.   Result := Byte(N) in [1, 2, 3];
  16. end;
  17.  
  18. begin
  19.   writeln(BoolToStr(TestHint1(258), 'yes', 'no'));
  20.   writeln(BoolToStr(TestHint2(258), 'yes', 'no')); // here 258 is converted to byte (it is cut to 2).
  21. end.
  22.  

The output is:
Quote
no
yes

FTurtle

  • Sr. Member
  • ****
  • Posts: 292
Re: Incosistent compiler hint
« Reply #5 on: February 11, 2016, 06:57:04 pm »
Code: Pascal  [Select][+][-]
  1.   writeln(BoolToStr(TestHint1(258), 'yes', 'no'));
  2.   writeln(BoolToStr(TestHint2(258), 'yes', 'no')); // here 258 is converted to byte (it is cut to 2).
  3.  

The output is:
Quote
no
yes

By the way, writeln is a compiler magic, so it is capable of many interesting things.
In particular, you would write simpler:

Code: Pascal  [Select][+][-]
  1.   writeln(TestHint1(258));
  2.   writeln(TestHint2(258)); // here 258 is converted to byte (it is cut to 2).
  3.  

with output:
Quote
FALSE
TRUE

 

TinyPortal © 2005-2018