Crystal: Nil type check fails when using ensure

Created on 24 Apr 2018  路  11Comments  路  Source: crystal-lang/crystal

require "spec"

describe "not_nil!" do
  a = 0
  a + 1 # > undefined method '+' for Nil (compile-time type is (Int32 | Nil))

  it "can be nil?" do
    a + 1 # > undefined method '+' for Nil (compile-time type is (Int32 | Nil))
    a.not_nil!
    a + 1 # > undefined method '+' for Nil (compile-time type is (Int32 | Nil))
  end
ensure
  a + 1 # > undefined method '+' for Nil (compile-time type is (Int32 | Nil))
end

Compile time type should not include Nil here?

Crystal 0.24.2 (2018-03-10)

LLVM: 5.0.1
Default target: x86_64-apple-macosx
bug compiler

All 11 comments

Reduced:

def foo(&block)
  block
end

foo do
  a = 0
  a + 1
ensure
  a + 1
end

More reduced:

begin
  a = 0
ensure
  a + 1 # undefined method '+' for Nil (compile-time type is (Int32 | Nil))
end

In general, there could be some error before assigning to a which would leave it as Nil in the ensure block. In this case with assigning a primitive to a local variable, there are probably not many chances (if any?) for a raise. But I don't think it would be wise to implement a special treatment for this.

Me neither, but maybe is a case to improve the error message.

Well the same argument would lead to

a = 0
a + 1 # undefined method '+' for Nil (compile-time type is (Int32 | Nil))

?

No, because with sequential expressions, a + 1 will never be executed if a = 0 raises. So a can't be Nil when this code is executed. But in an ensure block, it will even if a = 0 failed.

Reduced again:

def foo(&block)
  block
end

foo do
  a = 0
  foo do
    a + 1 # undefined method '+' for Nil (compile-time type is (Int32 | Nil))
  end
ensure
  a
end

This time the error above makes little sense.

Indeed. That shouldn't be supposed to error. Looks related to #5177

Btw, you can replace the outer foo do with begin.

With proc

begin
  a = 0
  a + 1
  -> do
    a + 1 # undefined method '+' for Nil (compile-time type is (Int32 | Nil))
  end.call
ensure
  a.not_nil! + 1 # This makes sense, at least when a is not primitive
end

Adding a statement after the proc makes thing even weirder:

begin
  a = 0
  a + 1 # undefined method '+' for Nil (compile-time type is (Int32 | Nil))
  -> do
    a.not_nil! + 1 # undefined method '+' for Nil (compile-time type is (Int32 | Nil))
  end.call
  a + 1 # undefined method '+' for Nil (compile-time type is (Int32 | Nil))
ensure
  a.not_nil! + 1 # This makes sense, at least when a is not primitive
end

Is there any update on this?

I'm looking for a workaround https://stackoverflow.com/q/59453429/1260906

Was this page helpful?
0 / 5 - 0 ratings

Related issues

will picture will  路  3Comments

cjgajard picture cjgajard  路  3Comments

nabeelomer picture nabeelomer  路  3Comments

asterite picture asterite  路  3Comments

Papierkorb picture Papierkorb  路  3Comments