Skip to content

is_a?(T) can break further type filtering if T is an uninstantiated generic #10831

Description

@HertzDevil

All of the expressions at the top should return true, and the NoReturn at the bottom should be B(Int32) since it simply swaps the order of the operands to && compared to the typeof immediately below:

class A; end
class B(T) < A; end

x = B(Int32).new.as(A)

x.is_a?(B       ) && x.is_a?(B       ) # => false
x.is_a?(B       ) && x.is_a?(B(Int32)) # => false
x.is_a?(B(Int32)) && x.is_a?(B       ) # => true
x.is_a?(B(Int32)) && x.is_a?(B(Int32)) # => true

typeof(x.is_a?(B       ) && x.is_a?(B       ) ? x : raise "") # => B(T)
typeof(x.is_a?(B       ) && x.is_a?(B(Int32)) ? x : raise "") # => NoReturn
typeof(x.is_a?(B(Int32)) && x.is_a?(B       ) ? x : raise "") # => B(Int32)
typeof(x.is_a?(B(Int32)) && x.is_a?(B(Int32)) ? x : raise "") # => B(Int32)

All the failures occur when x.is_a?(B) is used, which constrains the type of the x after the && to B(T).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions