PR# 19166 Expression of form "n.to_character_32.is_space" not compiling correctly to workbench bytecode

Problem Report Summary
Submitter: finnianr
Category: Compiler
Priority: Medium
Date: 2015/12/07
Class: Bug
Severity: Serious
Number: 19166
Release: 15.01.9.6535
Confidential: No
Status: Analyzed
Responsible:
Environment: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0
Synopsis: Expression of form "n.to_character_32.is_space" not compiling correctly to workbench bytecode

Description
When recompiling the class, the line of code sandwiched with asterisks in the following code fragment is not being compiled to workbench bytecode correctly. Finalized code does not seem to be affected.

class EL_ZSTRING_READABLE

feature -- Access

   leading_white_space: INTEGER
      local
         i, l_count: INTEGER; l_area: like area; c_i: CHARACTER
      do
         l_area := area; l_count := count
         from i := 0 until i = l_count loop
            c_i := l_area [i]
            -- `Unencoded_character' is space
            if c_i = Unencoded_character then
               -- *******************************************************
               if unencoded_code (i + 1).to_character_32.is_space then
               -- *******************************************************
                  Result := Result + 1
               else
                  i := l_count - 1 -- break out of loop
               end
            elseif c_i.is_space then
               Result := Result + 1
            else
               i := l_count - 1 -- break out of loop
            end
            i := i + 1
         end
      ensure
         substring_agrees: across substring (1, Result) as char all char.item.is_space end
      end
To Reproduce
The first time the code is compiled the expression "unencoded_code (i + 1).to_character_32.is_space" evaluates correctly on execution. (As shown by a test suite) However subsequent recompiles of edits to the class or it's descendants cause the expression in question to evaluate to False when it should evaluate to true, even though the value returned by unencoded_code (i + 1) is exactly the same as before. (NATURAL_32)

It can be temporarily fixed by forcing the routine to be recompiled, an operation which involves, commenting out the body of the routine, recompiling, then commenting the lines back in and recompiling. 

On a hunch I am going to try assigning "unencoded_code (i + 1).to_character_32" to an intermediate variable and see if that helps. Will report what happens.

Problem Report Interactions
From:finnianr    Date:2016/01/21    Download   
This code seems to work as a better workaround for the problem. 

   leading_white_space: INTEGER
      local
         i, l_count: INTEGER; l_area: like area; c_i: CHARACTER
         l_prop: like character_properties
      do
         l_area := area; l_count := count; l_prop := character_properties
         from i := 0 until i = l_count loop
            c_i := l_area [i]
            -- `Unencoded_character' is space
            if c_i = Unencoded_character then
               if l_prop.is_space (unencoded_item (i + 1)) then
                  Result := Result + 1
               else
                  i := l_count - 1 -- break out of loop
               end
            elseif c_i.is_space then
               Result := Result + 1
            else
               i := l_count - 1 -- break out of loop
            end
            i := i + 1
         end
      ensure
         substring_agrees: across substring (1, Result) as char all character_properties.is_space (char.item) end
      end

From:finnianr    Date:2016/01/21    Download   
Hi Alexander
I couldn't find a build for 15.02 to download. 
I have created a standalone project (attached) to test this issue on version Version 15.01.9. The test fails on a clean build for both the finalized and workbench application, so the issue is even worse then I thought. 

But if you force a workbench recompile of routines 

   {EL_READABLE_ZSTRING}.leading_white_space

   {EL_READABLE_ZSTRING}.trailing_white_space

the tests will pass for workbench mode.

To force a recompile: comment out the assignment below for each routine, recompile, then reintroduce the assignment. The test will then pass.

   uc_i := unencoded_item (i + 1)






Attachment: zstring-test.tar.gz     Size:115541
From:alexk_es    Date:2016/01/12    Status: Analyzed    Download   
Thank you for your report. So far we were unable to reproduce the issue with the recent version of EiffelStudio. Could you check that it still happens with EiffelStudio 15.12, please? If so, could you provide a self-contained example that demonstrates it?

From:finnianr    Date:2015/12/11    Download   
The problem has happened again, so the supposed workaround does not actually work.

From:finnianr    Date:2015/12/07    Download   
SUMMARY OF PROBLEM

4. This workaround makes the problem go away

   uc_i := unencoded_code (i + 1).to_character_32
   if uc_i.is_space then

From:finnianr    Date:2015/12/07    Download   
SUMMARY OF PROBLEM

1. With a clean build the line below executes correctly:

  if unencoded_code (i + 1).to_character_32.is_space then


2. F7 recompiles of class edits causes the line to fail to execute corrrectly.

3. Forced recompilation of routine causes the line to execute correctly again.


From:finnianr    Date:2015/12/07    Download   
After doing a class edit that normally causes a problem on recompile, I can confirm that assigning "unencoded_code (i + 1).to_character_32" to an intermediate variable fixes the problem. 

This should provide a clue as to where exactly the compilation problem is.