crystal icon indicating copy to clipboard operation
crystal copied to clipboard

BUG: `typeof` has no type

Open straight-shoota opened this issue 3 years ago • 5 comments

The following code triggers a compiler error:

input = 1
if input = input.is_a?(Int32)
  typeof(input) # BUG: `typeof(input)` at eval:3:3 has no type
end

Interestingly, when typeof(input) is used as a call argument, what was previously declared a compiler bug now becomes an unhandled compiler exception:

input = 1
if input = input.is_a?(Int32)
  puts typeof(input) # Unhandled exception: can't execute `puts(typeof(input))` at eval:3:3: `typeof(input)` has no type
end

Might be related to #9702 and #11054

straight-shoota avatar Nov 23 '21 20:11 straight-shoota

typeof is not that relevant it seems, the following triggers the same error:

input = 1

if input = input.is_a?(Int32)
  puts input
end

This already triggers the error.

beta-ziliani avatar Nov 26 '21 12:11 beta-ziliani

As I understand it, the typechecker tries to be smart by considering impossible cases:

x = nil
if x.is_a?(Int32)
  x + "" # OK, this will never be executed
end

The compiler infers that x should be Nil and Int32, in the body of the if, but that's impossible. In the example I posted before the compiler infers the same, but actually the execution will return a truthy value.

beta-ziliani avatar Sep 09 '22 14:09 beta-ziliani

The compiler infers that x should be Nil and Int32, in the body of the if

No, I think just Int32. Why also Nil?

asterite avatar Sep 09 '22 14:09 asterite

I don't know really, I'm just guessing what the typechecker is doing here, and my interpretation is compatible with its behavior.

beta-ziliani avatar Sep 09 '22 14:09 beta-ziliani

Type filters are applied according to variable names only, so they do not account for the possibility that the variables could be different yet. Another example:

x = 1
if x.is_a?(Int32) && (x = 'a'; "")
  p x
end

This applies the Int32 type filter on the second x, which is now a Char and does not produce a filter. Since Int32 & Char == NoReturn no type inference is done inside the then-clause. The correct behavior is to discard all type filters (positive or negative) on a variable whenever it is assigned, but possibly allow the truthy filter to take effect afterwards.

HertzDevil avatar Sep 09 '22 16:09 HertzDevil