SwensenSoftware/unquote

test always passes when custom function is a part of the quotation

ntr opened this issue · 4 comments

ntr commented

Following test always passes for me, but it should not:

let floatEqual a b =
    abs(a-b) < 1e-6

let coordsEqual (x1,y1) (x2,y2) =
    floatEqual x1 x2 && floatEqual y1 y2

let converter2 (a, b) = 
    Some (a+1.,b+1.)

[<Fact>]
let ``demo test``() =
    test <@ coordsEqual (33.03,-119.03) (converter2( 6.0, 6.0).Value) @>

My guess is that the engine cannot evaluate converter2 function and always returns true in this case. Probably should throw some kind of exception in this case.

Perhaps surprisingly, this looks like a bug in the F# compiler itself!

Observe the output of the standalone quotation in FSI:

> <@ coordsEqual (33.03,-119.03) (converter2( 6.0, 6.0).Value) @>;;
val it : Quotations.Expr<bool> =
  Let (tupledArg, NewTuple (Value (33.03), Value (-119.03)),
     Let (tupledArg,
          PropertyGet (Some (Call (None, converter2, [Value (6.0), Value (6.0)])),
                       Value, []),
          Let (x1, TupleGet (tupledArg, 0),
               Let (y1, TupleGet (tupledArg, 1),
                    Let (x2, TupleGet (tupledArg, 0),
                         Let (y2, TupleGet (tupledArg, 1),
                              Call (None, coordsEqual, [x1, y1, x2, y2])))))))

You can see that the quotation has been incorrectly captured: the first tupledArg binding is immediately shadowed by a seconded tupledArg, such that ultimately the final, reduced expression evaluated by Unquote is coordsEqual 7.0 7.0 7.0 7.0, which is true as Unquote reports. (note that Unquote can handle "custom" functions and almost all kinds of arbitrarily complex expressions).

I have reproduced this apparent bug in VS 2010, 2013, and 2015. I will close this issue and create an issue with the visualfsharp project.

Re-opening - turns out this is an Unquote bug after all caused by a false assumption about quotation variable identity.

Fixed w/ tests

ntr commented

Thank you.