Mirah miscompile on compound conditional.

29 views
Skip to first unread message

J. Scott Kasten

unread,
Feb 27, 2015, 3:04:26 AM2/27/15
to mi...@googlegroups.com
Hi guys,

Ran into something really strange and had a quite difficult time finding a
work around.

First, I wrote a complex conditional like so:

if @type1 or @type2 or @type3.str_attr.equals("__EMPTY__")
... block 1 ...
else
... block 2 ...
end

Here @type1, @type2, @type3 are all references to complex types in the
application. The first two pieces of the evaluation are of course implied
tests for "nil" to see if the references have been initialized or not. In
the final, I'm testing the value of a String attribute.

This compiled fine under Mirah 0.1.3 without complaint, however the Dalvik
dexer (Android target) blew chunks on the application "pre-link simulator"
run. It did not yeild any useful diagnostics and it took me almost 2
hours of trial and error to isolate the if condition above.

Once I isolated it to that conditional, I then tried various
reformulations to make it work. My first thought was to try various type
casts as I have seen some rare issues where Mirah needs a seemingly
redundant cast.

This form compile,

if (@type1 == TypeOne(nil)) or (@type2 == TypeTwo(nil)) or @type3.str_attr.equals("__EMPTY__")

and the dexer did not complain, but it consistenly evaluated to "true"
when it should not have.

I finally got this to work as expected:

if @type1 or @type2
... block 1 ...
elsif @type3.str_attr.equals("__EMPTY__")
... block 1 ...
else
... block 2 ...
end

Took me almost another 2 hours to reach that work around at last.

Has anyone seen something like this???

I have had code like this work, where I test for a valid reference before
calling a method on it:

if @type and @type.method()
...
end


Sorry I am sort of unable to test this against 0.1.4 at the moment. Would
appreciate any comments the compiler guys could give.

Thanks,

-S-

Nick Howard

unread,
Feb 27, 2015, 12:01:54 PM2/27/15
to mi...@googlegroups.com
Yes I've seen things like this. I think there are issues with how the parser / compiler interact with complex boolean expressions. Also, I don't think there's enough test coverage for this type of thing.

The way I've worked around it before is by breaking out temp variables for some of the conditionals which unwinds some of the nested expressions. It's really frustrating, but I haven't had time to dig into why it's happening.

Thanks for reporting the issue. I'd appreciate it if you could reduce it down to a self contained reproducible case and file an issue on github.

J. Scott Kasten

unread,
Feb 27, 2015, 4:19:26 PM2/27/15
to mi...@googlegroups.com
Thanks Nick, will see if I can get the trivial case working - or is that "breaking". :-)
--
Sent from my Android device.

J. Scott Kasten

unread,
Feb 27, 2015, 5:19:56 PM2/27/15
to mi...@googlegroups.com

OK, you're in luck. I have a reasonbly simple unit test for this. Will
post to github shortly.

-----------------------

package org.mirah.unit.test.ComplexConditional

#
# Std library support.
#
import java.lang.Object
import java.lang.String
import java.util.ArrayList
import java.util.HashMap




#####
#
# Demonstration type one.
#
class TypeOne
attr_reader val:int

def initialize
@val = 1
end
end

#####
#
# Demonstration type two.
#
class TypeTwo
attr_reader val:int

def initialize
@val = 2
end
end

#####
#
# Demonstration type three.
#
class TypeThree
attr_reader str:String

def initialize (str:String)
@str = str
end
end

#####
#
# Demonstration class for compiler issue.
#
class ComplexConditional
def initialize
@type1 = TypeOne(nil) # For type inference.
@type2 = TypeTwo(nil) # For type inference.
@type3 = TypeThree.new("Test Me!")
end

# Compiles, but Dalvik VM chokes on the byte code.
def case_01:boolean
if @type1 or @type2 or @type3.str.equals("__EMPTY__")
# If this line is called, the test FAILED.
result = false
else
# If this line is called, the test PASSED.
result = true
end

return result
end

# Compiles, Dalvik VM runs the byte code, but result is wrong.
def case_02:boolean
if (@type1 == TypeOne(nil)) or (@type2 == TypeTwo(nil)) or @type3.str.equals("__EMPTY__")
# If this line is called, the test FAILED.
result = false
else
# If this line is called, the test PASSED.
result = true
end

return result
end

# Compiles, runs correctly, but has redundant block.
def case_03:boolean
if @type1 or @type2
# If this line is called, the test FAILED.
result = false
elsif @type3.str.equals("__EMPTY__")
# If this line is called, the test FAILED.
result = false
else
# If this line is called, the test PASSED.
result = true
end

return result
end
end
Reply all
Reply to author
Forward
0 new messages