require "../../spec_helper"

describe "Semantic: class" do
  it "types Const#allocate" do
    assert_type("class Foo; end; Foo.allocate") { types["Foo"].as(NonGenericClassType) }
  end

  it "types Const#new" do
    assert_type("class Foo; end; Foo.new") { types["Foo"].as(NonGenericClassType) }
  end

  it "types Const#new#method" do
    assert_type("class Foo; def coco; 1; end; end; Foo.new.coco") { int32 }
  end

  it "types class inside class" do
    assert_type("class Foo; class Bar; end; end; Foo::Bar.allocate") { types["Foo"].types["Bar"] }
  end

  it "types instance variable" do
    result = assert_type(<<-CRYSTAL) { generic_class "Foo", int32 }
      class Foo(T)
        def set
          @coco = 2
        end
      end

      f = Foo(Int32).new
      f.set
      f
      CRYSTAL
    mod = result.program
    type = result.node.type.as(GenericClassInstanceType)
    type.instance_vars["@coco"].type.should eq(mod.nilable(mod.int32))
  end

  it "types generic of generic type" do
    assert_type(<<-CRYSTAL
      class Foo(T)
        def set
          @coco = 2
        end
      end

      f = Foo(Foo(Int32)).new
      f.set
      f
      CRYSTAL
    ) do
      foo = types["Foo"].as(GenericClassType)
      foo_i32 = foo.instantiate([int32] of TypeVar)
      _foo_foo_i32 = foo.instantiate([foo_i32] of TypeVar)
    end
  end

  it "types instance variable" do
    input = parse <<-CRYSTAL
      class Foo(T)
        def set(value : T)
          @coco = value
        end
      end

      f = Foo(Int32).new
      f.set 2

      g = Foo(Float64).new
      g.set 2.5
      g
      CRYSTAL
    result = semantic input
    mod, node = result.program, result.node.as(Expressions)
    foo = mod.types["Foo"].as(GenericClassType)

    node[1].type.should eq(foo.instantiate([mod.int32] of TypeVar))
    node[1].type.instance_vars["@coco"].type.should eq(mod.nilable(mod.int32))

    node[3].type.should eq(foo.instantiate([mod.float64] of TypeVar))
    node[3].type.instance_vars["@coco"].type.should eq(mod.nilable(mod.float64))
  end

  it "types instance variable on getter" do
    input = parse(<<-CRYSTAL).as(Expressions)
      class Foo(T)
        def set(value : T)
          @coco = value
        end

        def get
          @coco
        end
      end

      f = Foo(Int32).new
      f.set 2
      f.get

      g = Foo(Float64).new
      g.set 2.5
      g.get
      CRYSTAL
    result = semantic input
    mod, node = result.program, result.node.as(Expressions)

    node[3].type.should eq(mod.nilable(mod.int32))
    input.last.type.should eq(mod.nilable(mod.float64))
  end

  it "types recursive type" do
    input = parse(<<-CRYSTAL).as(Expressions)
      class Node
        def add
          if next_node = @next
            next_node.add
          else
            @next = Node.new
          end
        end
      end

      n = Node.new
      n.add
      n
      CRYSTAL
    result = semantic input
    mod, input = result.program, result.node.as(Expressions)
    node = mod.types["Node"].as(NonGenericClassType)

    node.lookup_instance_var("@next").type.should eq(mod.nilable(node))
    input.last.type.should eq(node)
  end

  it "types self inside method call without obj" do
    assert_type(<<-CRYSTAL) { types["Foo"] }
      class Foo
        def foo
          bar
        end

        def bar
          self
        end
      end

      Foo.new.foo
      CRYSTAL
  end

  it "types type var union" do
    assert_type(<<-CRYSTAL) { generic_class "Foo", union_of(int32, float64) }
      class Foo(T)
      end

      Foo(Int32 | Float64).new
      CRYSTAL
  end

  it "types class and subclass as one type" do
    assert_type(<<-CRYSTAL) { types["Foo"].virtual_type }
      class Foo
      end

      class Bar < Foo
      end

      a = Foo.new || Bar.new
      CRYSTAL
  end

  it "types class and subclass as one type" do
    assert_type(<<-CRYSTAL) { types["Foo"].virtual_type }
      class Foo
      end

      class Bar < Foo
      end

      class Baz < Foo
      end

      a = Bar.new || Baz.new
      CRYSTAL
  end

  it "types class and subclass as one type" do
    assert_type(<<-CRYSTAL) { types["Foo"].virtual_type }
      class Foo
      end

      class Bar < Foo
      end

      class Baz < Foo
      end

      a = Foo.new || Bar.new || Baz.new
      CRYSTAL
  end

  it "does automatic inference of new for generic types" do
    result = assert_type(<<-CRYSTAL) { generic_class "Box", int32 }
      class Box(T)
        def initialize(value : T)
          @value = value
        end
      end

      b = Box.new(10)
      CRYSTAL
    mod = result.program
    type = result.node.type.as(GenericClassInstanceType)
    type.type_vars["T"].type.should eq(mod.int32)
    type.instance_vars["@value"].type.should eq(mod.int32)
  end

  it "does automatic type inference of new for generic types 2" do
    result = assert_type(<<-CRYSTAL) { generic_class "Box", bool }
      class Box(T)
        def initialize(x, value : T)
          @value = value
        end
      end

      b1 = Box.new(1, 10)
      b2 = Box.new(1, false)
      CRYSTAL
    mod = result.program
    type = result.node.type.as(GenericClassInstanceType)
    type.type_vars["T"].type.should eq(mod.bool)
    type.instance_vars["@value"].type.should eq(mod.bool)
  end

  it "does automatic type inference of new for nested generic type" do
    nodes = parse(<<-CRYSTAL).as(Expressions)
      class Foo
        class Bar(T)
          def initialize(x : T)
            @x = x
          end
        end
      end

      Foo::Bar.new(1)
      CRYSTAL
    result = semantic nodes
    mod = result.program
    type = nodes.last.type.as(GenericClassInstanceType)
    type.type_vars["T"].type.should eq(mod.int32)
    type.instance_vars["@x"].type.should eq(mod.int32)
  end

  it "reports uninitialized constant" do
    assert_error "Foo.new",
      "undefined constant Foo"
  end

  it "reports undefined method when method inside a class" do
    assert_error "struct Int; def foo; 1; end; end; foo",
      "undefined local variable or method 'foo'"
  end

  it "reports undefined instance method" do
    assert_error "1.foo",
      "undefined method 'foo' for Int"
  end

  it "reports unknown class when extending" do
    assert_error "class Foo < Bar; end",
      "undefined constant Bar"
  end

  it "reports superclass mismatch" do
    assert_error "class Foo; end; class Bar; end; class Foo < Bar; end",
      "superclass mismatch for class Foo (Bar for Reference)"
  end

  it "reports wrong number of arguments for initialize" do
    assert_error <<-CRYSTAL, "wrong number of arguments"
      class Foo
        def initialize(x, y)
        end
      end

      f = Foo.new
      CRYSTAL
  end

  it "reports can't instantiate abstract class on new" do
    assert_error <<-CRYSTAL, "can't instantiate abstract class Foo"
      abstract class Foo; end
      Foo.new
      CRYSTAL
  end

  it "reports can't instantiate abstract class on allocate" do
    assert_error <<-CRYSTAL, "can't instantiate abstract class Foo"
      abstract class Foo; end
      Foo.allocate
      CRYSTAL
  end

  it "doesn't lookup new in supermetaclass" do
    assert_type(<<-CRYSTAL) { generic_class "Foo", int32 }
      class Foo(T)
      end

      Reference.new
      Foo(Int32).new
      CRYSTAL
  end

  it "errors when wrong arguments for new" do
    assert_error "Reference.new 1",
      "wrong number of arguments"
  end

  it "types virtual method of generic class" do
    assert_type(<<-CRYSTAL) { int32 }
      class Object
        def foo
          bar
        end

        def bar
          'a'
        end
      end

      class Foo(T)
        def bar
          1
        end
      end

      Foo(Int32).new.foo
      CRYSTAL
  end

  it "allows defining classes inside modules or classes with ::" do
    input = parse(<<-CRYSTAL)
      class Foo
      end

      class Foo::Bar
      end
      CRYSTAL
    result = semantic input
    mod = result.program
    mod.types["Foo"].types["Bar"].as(NonGenericClassType)
  end

  it "doesn't lookup type in parents' namespaces, and lookups and in program" do
    code = "
      class Bar
      end

      module Mod
        class Bar
        end

        class Foo
          def self.foo(x : Bar)
            1
          end

          def self.foo(x : ::Bar)
            'a'
          end
        end
      end
      "

    assert_type(<<-CRYSTAL) { int32 }
      #{code}
      Mod::Foo.foo(Mod::Bar.new)
      CRYSTAL

    assert_type(<<-CRYSTAL) { char }
      #{code}
      Mod::Foo.foo(Bar.new)
      CRYSTAL
  end

  it "type def does not reopen type from parent namespace (#11181)" do
    assert_type <<-CRYSTAL, inject_primitives: false { types["Baz"].types["Foo"].types["Bar"].metaclass }
      class Foo::Bar
      end

      module Baz
        class Foo::Bar
        end
      end

      Baz::Foo::Bar
      CRYSTAL
  end

  it "finds in global scope if includes module" do
    assert_type(<<-CRYSTAL) { int32 }
      class Baz
      end

      module Foo
        class Bar
          include Foo

          Baz
        end
      end

      1
      CRYSTAL
  end

  it "allows instantiating generic class with number" do
    assert_type(<<-CRYSTAL) { generic_class "Foo", 1.int32 }
      class Foo(T)
      end

      Foo(1).new
      CRYSTAL
  end

  it "uses number type var in class method" do
    assert_type(<<-CRYSTAL) { int32 }
      class Foo(T)
        def self.foo
          T
        end
      end

      Foo(1).foo
      CRYSTAL
  end

  it "uses self as type var" do
    assert_type(<<-CRYSTAL) { generic_class "Foo", types["Bar"] }
      class Foo(T)
      end

      class Bar
        def self.coco
          Foo(self)
        end
      end

      Bar.coco.new
      CRYSTAL
  end

  it "uses self as type var" do
    assert_type(<<-CRYSTAL) { generic_class "Foo", types["Baz"] }
      class Foo(T)
      end

      class Bar
        def self.coco
          Foo(self)
        end
      end

      class Baz < Bar
      end

      Baz.coco.new
      CRYSTAL
  end

  it "infers generic type after instance was created with explicit type" do
    assert_type(<<-CRYSTAL) { int32 }
      class Foo(T)
        def initialize(@x : T)
        end

        def x
          @x
        end
      end

      foo1 = Foo(Bool).new(true)
      foo2 = Foo.new(1)
      foo2.x
      CRYSTAL
  end

  it "errors when creating Value" do
    assert_error "Value.allocate", "can't instantiate abstract struct Value"
  end

  it "errors when creating Number" do
    assert_error "Number.allocate", "can't instantiate abstract struct Number"
  end

  it "reads an object instance var" do
    assert_type(<<-CRYSTAL) { int32 }
      class Foo
        def initialize(@x : Int32)
        end
      end

      foo = Foo.new(1)
      foo.@x
      CRYSTAL
  end

  it "reads a virtual type instance var" do
    assert_type(<<-CRYSTAL) { int32 }
      class Foo
        def initialize(@x : Int32)
        end
      end

      class Bar < Foo
      end

      foo = Foo.new(1) || Bar.new(2)
      foo.@x
      CRYSTAL
  end

  it "errors if reading non-existent ivar" do
    assert_error <<-CRYSTAL, "can't infer the type of instance variable '@y' of Foo"
      class Foo
      end

      foo = Foo.new
      foo.@y
      CRYSTAL
  end

  it "errors if reading ivar from non-ivar container" do
    assert_error <<-CRYSTAL, "can't use instance variables inside primitive types (at Int32)"
      1.@y
      CRYSTAL
  end

  it "reads an object instance var from a union type" do
    assert_type(<<-CRYSTAL) { union_of(int32, char) }
      class Foo
        def initialize(@x : Int32)
        end
      end

      class Bar
        def initialize(@y : Int32, @x : Char)
        end
      end

      foo = Foo.new(1)
      bar = Bar.new(2, 'a')
      union = foo || bar
      union.@x
      CRYSTAL
  end

  it "says that instance vars are not allowed in metaclass" do
    assert_error <<-CRYSTAL, "@instance_vars are not yet allowed in metaclasses: use @@class_vars instead"
      module Foo
        def self.foo
          @foo
        end
      end

      Foo.foo
      CRYSTAL
  end

  it "doesn't use initialize from base class" do
    assert_error <<-CRYSTAL, "wrong number of arguments for 'Bar.new' (given 1, expected 2)"
      class Foo
        def initialize(x)
        end
      end

      class Bar < Foo
        def initialize(x, y)
        end
      end

      Bar.new(1)
      CRYSTAL
  end

  it "doesn't use initialize from base class with virtual type" do
    assert_error <<-CRYSTAL, "wrong number of arguments for 'Bar#initialize' (given 1, expected 2)", inject_primitives: true
      class Foo
        def initialize(x)
        end
      end

      class Bar < Foo
        def initialize(x, y)
        end
      end

      klass = 1 == 1 ? Foo : Bar
      klass.new(1)
      CRYSTAL
  end

  it "errors if using underscore in generic class" do
    assert_error <<-CRYSTAL, "can't use underscore as generic type argument"
      class Foo(T)
      end

      Foo(_).new
      CRYSTAL
  end

  it "types bug #168 (it inherits instance var even if not mentioned in initialize)" do
    assert_error <<-CRYSTAL, "can't infer the type of instance variable '@x' of Foo"
      class Foo
        def foo
          x = @x
          if x
            x.foo
          else
            1
          end
        end
      end

      class Bar < Foo
        def initialize(@x : Foo)
        end
      end

      Bar.new(Foo.new).foo
      CRYSTAL
  end

  it "doesn't mark instance variable as nilable if calling another initialize" do
    assert_type(<<-CRYSTAL) { int32 }
      class Foo
        def initialize(x, y)
          initialize(x)
        end

        def initialize(@x : Int32)
        end

        def x
          @x
        end
      end

      foo = Foo.new(1, 2)
      foo.x
      CRYSTAL
  end

  it "says wrong number of arguments for abstract class new" do
    assert_error <<-CRYSTAL, "wrong number of arguments for 'Foo.new' (given 1, expected 0)"
      abstract class Foo
      end

      Foo.new(1)
      CRYSTAL
  end

  it "says wrong number of arguments for abstract class new (2)" do
    assert_error <<-CRYSTAL, "wrong number of arguments for 'Foo.new' (given 0, expected 1)"
      abstract class Foo
        def initialize(x)
        end
      end

      Foo.new
      CRYSTAL
  end

  it "can't reopen as struct" do
    assert_error <<-CRYSTAL, "Foo is not a struct, it's a class"
      class Foo
      end

      struct Foo
      end
      CRYSTAL
  end

  it "can't reopen as module" do
    assert_error <<-CRYSTAL, "Foo is not a module, it's a class"
      class Foo
      end

      module Foo
      end
      CRYSTAL
  end

  it "errors if reopening non-generic class as generic" do
    assert_error <<-CRYSTAL, "Foo is not a generic class"
      class Foo
      end

      class Foo(T)
      end
      CRYSTAL
  end

  it "errors if reopening generic class with different type vars" do
    assert_error <<-CRYSTAL, "type var must be T, not U"
      class Foo(T)
      end

      class Foo(U)
      end
      CRYSTAL
  end

  it "errors if reopening generic class with different type vars (2)" do
    assert_error <<-CRYSTAL, "type vars must be A, B, not C"
      class Foo(A, B)
      end

      class Foo(C)
      end
      CRYSTAL
  end

  it "errors if reopening generic class with different splat index" do
    assert_error <<-CRYSTAL, "type var must be A, not *A"
      class Foo(A)
      end

      class Foo(*A)
      end
      CRYSTAL
  end

  it "errors if reopening generic class with different splat index (2)" do
    assert_error <<-CRYSTAL, "type var must be *A, not A"
      class Foo(*A)
      end

      class Foo(A)
      end
      CRYSTAL
  end

  it "errors if reopening generic class with different splat index (3)" do
    assert_error <<-CRYSTAL, "type vars must be *A, B, not A, *B"
      class Foo(*A, B)
      end

      class Foo(A, *B)
      end
      CRYSTAL
  end

  it "allows declaring a variable in an initialize and using it" do
    assert_type(<<-CRYSTAL, inject_primitives: true) { int32 }
      class Foo
        def initialize
          @x = uninitialized Int32
          @x + 1
        end

        def x
          @x
        end
      end

      Foo.new.x
      CRYSTAL
  end

  it "allows using self in class scope" do
    assert_type(<<-CRYSTAL) { int32 }
      class Foo
        def self.foo
          1
        end

        @@x = self.foo.as(Int32)

        def self.x
          @@x
        end
      end

      Foo.x
      CRYSTAL
  end

  it "can't use implicit initialize if defined in parent" do
    assert_error <<-CRYSTAL, "wrong number of arguments for 'Bar.new' (given 0, expected 1)"
      class Foo
        def initialize(x)
        end
      end

      class Bar < Foo
      end

      Bar.new
      CRYSTAL
  end

  it "doesn't error on new on abstract virtual type class" do
    assert_type(<<-CRYSTAL, inject_primitives: true) { int32 }
      abstract class Foo
      end

      class Bar < Foo
        def initialize(@x : Int32)
        end

        def x
          @x
        end
      end

      ptr = Pointer(Foo.class).malloc(1_u64)
      ptr.value = Bar
      bar = ptr.value.new(1)
      bar.x
      CRYSTAL
  end

  it "says no overload matches for class new" do
    assert_error <<-CRYSTAL, "expected argument #1 to 'Foo.new' to be Int32, not Char"
      class Foo
        def self.new(x : Int32)
        end
      end

      Foo.new 'a'
      CRYSTAL
  end

  it "correctly types #680" do
    assert_type(<<-CRYSTAL) { nilable int32 }
      class Foo
        def initialize(@method : Int32?)
        end

        def method
          @method
        end
      end

      class Bar < Foo
        def initialize
          super(method)
        end
      end

      Bar.new.method
      CRYSTAL
  end

  it "correctly types #680 (2)" do
    assert_error <<-CRYSTAL, "instance variable '@method' of Foo must be Int32, not Nil"
      class Foo
        def initialize(@method : Int32)
        end

        def method
          @method
        end
      end

      class Bar < Foo
        def initialize
          super(method)
        end
      end

      Bar.new.method
      CRYSTAL
  end

  it "can invoke method on abstract type without subclasses nor instances" do
    assert_type(<<-CRYSTAL) { int32 }
      require "prelude"

      abstract class Foo
      end

      a = [] of Foo
      a.each &.foo
      1
      CRYSTAL
  end

  it "can invoke method on abstract generic type without subclasses nor instances" do
    assert_type(<<-CRYSTAL) { int32 }
      require "prelude"

      abstract class Foo(T)
      end

      a = [] of Foo(Int32)
      a.each &.foo
      1
      CRYSTAL
  end

  it "can invoke method on abstract generic type with subclasses but no instances" do
    assert_type(<<-CRYSTAL) { int32 }
      require "prelude"

      abstract class Foo(T)
      end

      class Bar(T) < Foo(T)
        def foo
        end
      end

      a = [] of Foo(Int32)
      a.each &.foo
      1
      CRYSTAL
  end

  it "doesn't crash on instance variable assigned a proc, and never instantiated (#923)" do
    assert_type(<<-CRYSTAL) { nil_type }
      class Klass
        def self.f(arg)
        end

        @a  : Proc(String, Nil) = ->f(String)
      end
      CRYSTAL
  end

  it "errors if declares class inside if" do
    assert_error <<-CRYSTAL, "can't declare class dynamically"
      if 1 == 2
        class Foo; end
      end
      CRYSTAL
  end

  it "can mark initialize as private" do
    assert_error <<-CRYSTAL, "private method 'new' called for Foo"
      class Foo
        private def initialize
        end
      end

      Foo.new
      CRYSTAL
  end

  it "errors if creating instance before typing instance variable" do
    assert_error <<-CRYSTAL, "instance variable '@x' of Foo must be Int32"
      class Foo
        Foo.new

        @x : Int32

        def initialize
          @x = false
        end
      end
      CRYSTAL
  end

  it "errors if assigning superclass to declared instance var" do
    assert_error <<-CRYSTAL, "instance variable '@bar' of Main must be Bar"
      class Foo
      end

      class Bar < Foo
      end

      class Main
        @bar : Bar

        def initialize
          @bar = Foo.new
        end
      end

      Main.new
      CRYSTAL
  end

  it "hoists instance variable initializer" do
    assert_type(<<-CRYSTAL, inject_primitives: true) { int32 }
      a = Foo.new.bar + 1

      class Foo
        @bar = 1

        def bar
          @bar
        end
      end

      a
      CRYSTAL
  end

  it "doesn't mix classes on definition (#2352)" do
    assert_type(<<-CRYSTAL) { int32 }
      class Baz
      end

      class Moo::Baz::B
        def self.foo
          1
        end
      end

      Moo::Baz::B.foo
      CRYSTAL
  end

  it "errors if using read-instance-var with non-typed variable" do
    assert_error <<-CRYSTAL, "can't infer the type of instance variable '@foo' of Foo"
      class Foo
        def foo
          @foo
        end
      end

      f = Foo.new
      f.@foo
      CRYSTAL
  end

  it "doesn't crash with top-level initialize (#2601)" do
    assert_type(<<-CRYSTAL) { int32 }
      def initialize
        1
      end

      initialize
      CRYSTAL
  end

  it "inherits self (#2890)" do
    assert_type(<<-CRYSTAL) { types["Foo"].metaclass }
      class Foo
        class Bar < self
        end
      end

      {{Foo::Bar.superclass}}
      CRYSTAL
  end

  it "inherits Gen(self) (#2890)" do
    assert_type(<<-CRYSTAL) { types["Foo"].metaclass }
      class Gen(T)
        def self.t
          T
        end
      end

      class Foo
        class Bar < Gen(self)
        end
      end

      Foo::Bar.t
      CRYSTAL
  end

  it "errors if inheriting Gen(self) and there's no self (#2890)" do
    assert_error <<-CRYSTAL, "there's no self in this scope"
      class Gen(T)
        def self.t
          T
        end
      end

      class Bar < Gen(self)
      end

      Bar.t
      CRYSTAL
  end

  it "preserves order of instance vars (#3050)" do
    result = semantic(<<-CRYSTAL)
      class Foo
        @x = uninitialized Int32
        @y : Int32

        def initialize(@y)
        end
      end
      CRYSTAL
    instance_vars = result.program.types["Foo"].instance_vars.to_a.map(&.[0])
    instance_vars.should eq(%w(@x @y))
  end

  it "errors if inherits from module" do
    assert_error <<-CRYSTAL, "Moo is not a class, it's a module"
      module Moo
      end

      class Foo < Moo
      end
      CRYSTAL
  end

  it "errors if inherits from metaclass" do
    assert_error <<-CRYSTAL, "Foo.class is not a class, it's a metaclass"
      class Foo
      end

      alias FooClass = Foo.class

      class Bar < FooClass
      end
      CRYSTAL
  end

  it "can use short name for top-level type" do
    assert_type(<<-CRYSTAL) { types["T"] }
      class T
      end

      T.new
      CRYSTAL
  end

  it "errors on no method found on abstract class, class method (#2241)" do
    assert_error <<-CRYSTAL, "undefined method 'bar' for Foo.class"
      abstract class Foo
      end

      Foo.bar
      CRYSTAL
  end

  it "inherits self twice (#5495)" do
    assert_type(<<-CRYSTAL) { tuple_of [types["Foo"].metaclass, types["Foo"].metaclass] }
      class Foo
        class Bar < self
        end

        class Baz < self
        end
      end

      { {{ Foo::Bar.superclass }}, {{ Foo::Baz.superclass }} }
      CRYSTAL
  end

  it "types as no return if calling method on abstract class with all abstract subclasses (#6996)" do
    assert_type(<<-CRYSTAL) { no_return }
      require "prelude"

      abstract class Foo
        abstract def foo?
      end

      abstract class Bar < Foo
      end

      Pointer(Foo).malloc(1_u64).value.foo?
      CRYSTAL
  end

  it "types as no return if calling method on abstract class with generic subclasses but no instances (#6996)" do
    assert_type(<<-CRYSTAL) { no_return }
      require "prelude"

      abstract class Foo
        abstract def foo?
      end

      class Bar(T) < Foo
        def foo?
          true
        end
      end

      Pointer(Foo).malloc(1_u64).value.foo?
      CRYSTAL
  end

  it "types as no return if calling method on abstract generic class (#6996)" do
    assert_type(<<-CRYSTAL) { no_return }
      require "prelude"

      abstract class Foo(T)
        abstract def foo?
      end

      Pointer(Foo(Int32)).malloc(1_u64).value.foo?
      CRYSTAL
  end

  it "types as no return if calling method on generic class with subclasses (#6996)" do
    assert_type(<<-CRYSTAL) { no_return }
      require "prelude"

      abstract class Foo(T)
        abstract def foo?
      end

      abstract class Bar(T) < Foo(T)
      end

      Bar(Int32)

      Pointer(Foo(Int32)).malloc(1_u64).value.foo?
      CRYSTAL
  end

  it "doesn't try to instantiate abstract generic struct when iterating subtypes (#9621)" do
    assert_type(<<-CRYSTAL) { int32 }
      require "prelude"

      abstract struct Base; end
      struct A < Base; end
      struct B < Base; end
      abstract struct Gen(T) < Base; end
      struct C < Gen(Int32); end

      [A, B].each &.new

      1
      CRYSTAL
  end
end
