Search code examples
unit-testingcompiler-errorscrystal-lang

Error: undefined method 'x' for Nil (compile-time type is (Point | Nil))


I'm writing a test that checks coordinates of a point to have a certain value, e.g.:

it "should work" do
   p = do_something   # returns a Point(x, y)
   p.x.should eq 0    # errors (see below)
end

But it fails to compile with the following error:

Error: undefined method 'x' for Nil (compile-time type is (Point | Nil))

I was able to reduce the issue to the following minimal example which does not compile:

struct Point
    property x : Int32
    property y : Int32
    def initialize(@x, @y)
    end
end

begin
    p = Point.new 0, 0
ensure
    p.x == 0
end

Which throws the same error:

❯ crystal src/debug.cr
Showing last frame. Use --error-trace for full trace.

In src/debug.cr:11:7

 11 | p.x == 0
        ^
Error: undefined method 'x' for Nil (compile-time type is (Point | Nil))

Now, I came across a similar bug report on the programming language Github tracker: Nil type check fails when using ensure, apparently this is an issue that has to be addressed by the Crystal language.

My question is, how can I check the value of p.x without triggering this error in an ensure block? I'm kind of clueless how to access this.

For context, I'm writing a cryptographic library which operates on points on the an elliptic curve, so it's everything about checking the coordinates here.


Solution

  • There is a couple of possibilities here, e.g. you can replace the line p.x == 0 with either of:

    1. p.try &.x == 0 - p will be checked for being Nil, and only when it's not Nil, the comparison will run.
    2. p.not_nil!.x == 0 - you command the compiler that p can never be Nil, but if it actually happens to be nil, the line will raise at runtime.