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
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