require "../../spec_helper" describe "Code gen: proc" do it "call simple proc literal" do run("x = -> { 1 }; x.call").to_i.should eq(1) end it "call proc literal with arguments" do run("f = ->(x : Int32) { x &+ 1 }; f.call(41)").to_i.should eq(42) end it "call proc literal with return type" do run(<<-CRYSTAL).to_b.should be_true f = -> : Int32 | Float64 { 1 } x = f.call x.is_a?(Int32) && x == 1 CRYSTAL end it "call proc pointer" do run("def foo; 1; end; x = ->foo; x.call").to_i.should eq(1) end it "call proc pointer with args" do run(<<-CRYSTAL).to_i.should eq(3) def foo(x, y) x &+ y end f = ->foo(Int32, Int32) f.call(1, 2) CRYSTAL end it "call proc pointer of instance method" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize @x = 1 end def coco @x end end foo = Foo.new f = ->foo.coco f.call CRYSTAL end it "call proc pointer of instance method that raises" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Foo def coco raise "foo" end end foo = Foo.new f = ->foo.coco f.call rescue 1 CRYSTAL end it "codegens proc with another var" do run(<<-CRYSTAL) def foo(x) bar(x, -> {}) end def bar(x, proc) end foo(1) CRYSTAL end it "codegens proc that returns a virtual type" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def coco; 1; end end class Bar < Foo def coco; 2; end end x = -> { Foo.new || Bar.new } x.call.coco CRYSTAL end it "codegens proc that accepts a union and is called with a single type" do run(<<-CRYSTAL).to_i.should eq(2) struct Float def &+(other) self + other end end f = ->(x : Int32 | Float64) { x &+ 1 } f.call(1).to_i! CRYSTAL end it "makes sure that proc pointer is transformed after type inference" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Bar def initialize(@x : Int32) end def x @x end end class Foo def on_something Bar.new(1) end end def _on_(p : Foo*) p.value.on_something.x end c = ->_on_(Foo*) a = Foo.new c.call(pointerof(a)) CRYSTAL end it "binds function pointer to associated call" do run(<<-CRYSTAL).to_i.should eq(12) class Foo def initialize(@e : Int32) end def on_something @e end end def _on_(p : Foo*) p.value.on_something end c = ->_on_(Foo*) a = Foo.new(12) a.on_something c.call(pointerof(a)) CRYSTAL end it "call simple proc literal with return" do run("x = -> { return 1 }; x.call").to_i.should eq(1) end it "calls proc pointer with union (passed by value) arg" do run(<<-CRYSTAL).to_i.should eq(1) struct Number def abs; self; end end f = ->(x : Int32 | Float64) { x.abs } f.call(1 || 1.5).to_i! CRYSTAL end it "allows passing proc type to C automatically" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" lib LibC fun qsort(base : Void*, nel : LibC::SizeT, width : LibC::SizeT, callback : (Void*, Void* -> Int32)) end ary = [3, 1, 4, 2] LibC.qsort(ary.to_unsafe.as(Void*), LibC::SizeT.new(ary.size), LibC::SizeT.new(sizeof(Int32)), ->(a : Void*, b : Void*) { a = a.as(Int32*) b = b.as(Int32*) a.value <=> b.value }) ary[0] CRYSTAL end it "allows proc pointer where self is a class" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def self.bla 1 end end f = ->Foo.bla f.call CRYSTAL end it "codegens proc literal hard type inference (1)" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Foo def initialize(@x : NoReturn) end def x @x end end def foo(s) Foo.new(s.x) end def bar ->(s : Foo) { ->foo(Foo) } end bar 1 CRYSTAL end it "automatically casts proc that returns something to proc that returns void" do run(<<-CRYSTAL).to_i.should eq(1) class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end def foo(x : ->) x.call end foo ->{ Global.x = 1 } Global.x CRYSTAL end it "allows proc type of enum type" do run(<<-CRYSTAL).to_i.should eq(1) lib LibFoo enum MyEnum X = 1 end end ->(x : LibFoo::MyEnum) { x }.call(LibFoo::MyEnum::X) CRYSTAL end it "allows proc type of enum type with base type" do run(<<-CRYSTAL).to_i.should eq(1) lib LibFoo enum MyEnum : UInt16 X = 1 end end ->(x : LibFoo::MyEnum) { x }.call(LibFoo::MyEnum::X) CRYSTAL end it "codegens nilable proc type (1)" do run(<<-CRYSTAL).to_i.should eq(3) a = 1 == 2 ? nil : ->{ 3 } if a a.call else 4 end CRYSTAL end it "codegens nilable proc type (2)" do run(<<-CRYSTAL).to_i.should eq(4) a = 1 == 1 ? nil : ->{ 3 } if a a.call else 4 end CRYSTAL end it "codegens nilable proc type dispatch (1)" do run(<<-CRYSTAL).to_i.should eq(3) def foo(x : -> U) forall U x.call end def foo(x : Nil) 0 end a = 1 == 1 ? (->{ 3 }) : nil foo(a) CRYSTAL end it "codegens nilable proc type dispatch (2)" do run(<<-CRYSTAL).to_i.should eq(0) def foo(x : -> U) forall U x.call end def foo(x : Nil) 0 end a = 1 == 1 ? nil : ->{ 3 } foo(a) CRYSTAL end it "builds proc type from fun" do codegen(<<-CRYSTAL) lib LibC fun foo : -> end x = LibC.foo x.call CRYSTAL end it "builds nilable proc type from fun" do codegen(<<-CRYSTAL) lib LibC fun foo : (->)? end x = LibC.foo if x x.call end CRYSTAL end it "assigns nil and proc to nilable proc type" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize end def x=(@x : (-> Int32)?) end def x @x end end foo = Foo.new foo.x = nil foo.x = -> { 1 } z = foo.x if z z.call else 2 end CRYSTAL end it "allows invoking proc literal with smaller type" do run(<<-CRYSTAL).to_i.should eq(1) struct Nil def to_i! 0 end end f = ->(x : Int32 | Nil) { x } f.call(1).to_i! CRYSTAL end it "does new on proc type" do run(<<-CRYSTAL).to_i.should eq(3) struct Proc def self.new(&block : self) block end end alias Func = Int32 -> Int32 a = 2 f = Func.new { |x| x &+ a } f.call(1) CRYSTAL end it "allows invoking a function with a subtype" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def x 1 end end class Bar < Foo def x 2 end end f = ->(foo : Foo) { foo.x } f.call Bar.new CRYSTAL end it "allows invoking a function with a subtype when defined as block spec" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def x 1 end end class Bar < Foo def x 2 end end def func(&block : Foo -> U) forall U block end f = func { |foo| foo.x } f.call Bar.new CRYSTAL end it "allows redefining fun" do run(<<-CRYSTAL).to_i.should eq(2) fun foo : Int32 1 end fun foo : Int32 2 end foo CRYSTAL end it "passes block to another function (bug: mangling of both methods was the same)" do run(<<-CRYSTAL).to_i.should eq(1) def foo(&block : ->) foo(block) end def foo(block) 1 end foo { } CRYSTAL end it "codegens proc with union type that returns itself" do run(<<-CRYSTAL).to_i.should eq(1) a = 1 || 1.5 foo = ->(x : Int32 | Float64) { x } foo.call(a) foo.call(a).to_i! CRYSTAL end it "codegens issue with missing byval in proc literal inside struct" do run(<<-CRYSTAL).to_string.should eq("bar") require "prelude" struct Params def foo params = [] of {String} params << {"foo"} params << {"bar"} params.sort! { |x, y| x[0] <=> y[0] } params[0][0] end end Params.new.foo CRYSTAL end it "codegens proc that references struct (bug)" do run(<<-CRYSTAL).to_i.should_not eq(42) class Ref end class Context def initialize @x = Ref.new end def run @x.object_id end def it(&block) block.call end end struct Foo def initialize @x = 0 @y = 0 @z = 42 @w = 0 end end context = Context.new context.it do Foo.new end context.run CRYSTAL end it "codegens captured block that returns tuple" do codegen(<<-CRYSTAL) def foo(&block) block end block = foo do {0, 0, 42, 0} end block.call CRYSTAL end it "allows using proc arg name shadowing local variable" do run(<<-CRYSTAL).to_i.should eq(1) a = 1 f = ->(a : String) { } a CRYSTAL end it "codegens proc that accepts array of type" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" class Foo def foo 1 end end class Bar < Foo def foo 2 end end def foo(&block : Array(Foo) -> Foo) block end block = foo { |elems| Bar.new } elems = [Bar.new, Foo.new] bar = block.call elems bar.foo CRYSTAL end it "gets proc to lib fun (#504)" do codegen(<<-CRYSTAL) lib LibFoo fun bar end ->LibFoo.bar CRYSTAL end it "gets proc to lib fun with parameter types" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(8)) #include int32_t foo(int32_t x, int32_t y) { return x + y; } C lib LibFoo fun foo(x : Int32, y : Int32) : Int32 end fn = ->LibFoo.foo(Int32, Int32) fn.call(3, 5) CRYSTAL end it "gets proc to lib fun with compatible parameter types" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(0x1235)) void *foo(void *x) { return (void *)((char *)x + 1); } C lib LibFoo fun foo(x : Void*) : Void* end x = Pointer(UInt8).new(0x1234) fn = ->LibFoo.foo(UInt8*) fn.call(x).address CRYSTAL end it "gets proc to lib fun with compatible `#to_unsafe` type" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(42)) #include int32_t foo(int32_t x) { return x * 2; } C lib LibFoo fun foo(x : Int32) : Int32 end class Foo def to_unsafe 21 end end fn = ->LibFoo.foo(Foo) fn.call(Foo.new) CRYSTAL end it "gets proc to variadic lib fun with parameter types" do test_c(<<-C, <<-CRYSTAL, &.to_i.should eq(1110)) #include #include int32_t foo(int32_t n, ...) { va_list args; va_start(args, n); int32_t sum = 0; for (; n > 0; --n) sum += va_arg(args, int32_t); return sum; } C lib LibFoo fun foo(n : Int32, ...) : Int32 end fn = ->LibFoo.foo(Int32, Int32, Int32, Int32) fn.call(3, 10, 100, 1000) CRYSTAL end it "gets same pointer from proc pointers to lib fun with compatible types" do test_c(<<-C, <<-CRYSTAL, &.to_b.should be_true) void foo(void *x) { } C lib LibFoo fun foo(x : Void*) end a = ->LibFoo.foo b = ->LibFoo.foo(Void*) c = ->LibFoo.foo(UInt8*) a.pointer == b.pointer && a.pointer == c.pointer CRYSTAL end it "codegens proc to implicit self in constant (#647)" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" module Foo def self.blah 1 end H = ->{ blah } end Foo::H.call CRYSTAL end it "passes proc as &->expr to method that yields" do run(<<-CRYSTAL).to_i.should eq(123) def foo yield end foo &->{ 123 } CRYSTAL end it "mangles strings in such a way they don't conflict with funs (#1006)" do run(<<-CRYSTAL).to_i.should eq(123) a = :foo fun foo : Int32 123 end foo CRYSTAL end it "gets proc pointer using virtual type (#1337)" do run(<<-CRYSTAL).to_i.should eq(2) class Foo def foo 1 end end class Bar < Foo def foo 2 end end def foo(a : Foo) a.foo end bar = ->foo(Foo) bar.call(Bar.new) CRYSTAL end it "uses alias of proc with virtual type (#1347)" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" class Class1 def foo 1 end end class Class2 < Class1 def foo 2 end end module Foo alias Callback = Class1 -> @@callbacks = Hash(String, Callback).new def self.add(name, &block : Callback) @@callbacks[name] = block end def self.call @@callbacks.each_value(&.call(Class2.new)) end end class Global @@x = 0 def self.x=(@@x) end def self.x @@x end end Foo.add("foo") do |a| Global.x = a.foo end Foo.call Global.x CRYSTAL end it "doesn't crash on #2196" do run(<<-CRYSTAL).to_i.should eq(42) x = 42 z = if x.is_a?(Int32) x else y = x ->{ y } end z.is_a?(Int32) ? z : 0 CRYSTAL end it "accesses T in macros as a TupleLiteral" do run(<<-CRYSTAL).to_string.should eq("TupleLiteral") struct Proc def t {{ T.class_name }} end end ->(x : Int32) { 'a' }.t CRYSTAL end it "codegens proc in instance var initialize (#3016)" do run(<<-CRYSTAL).to_i.should eq(42) class Foo @f : -> Int32 = ->foo def self.foo 42 end end Foo.new.@f.call CRYSTAL end it "codegens proc of generic type" do codegen(<<-CRYSTAL) class Gen(T) end class Foo < Gen(Int32) end f = ->(x : Gen(Int32)) {} f.call(Foo.new) CRYSTAL end it "executes proc pointer on primitive" do run(<<-CRYSTAL).to_i.should eq(21) a = 1 f = ->a.&+(Int32) f.call(20) CRYSTAL end it "can pass Proc(T) to Proc(Nil) in type restriction (#8964)" do run(<<-CRYSTAL).to_i.should eq(2) def foo(x : Proc(Nil)) x end a = 1 proc = foo(->{ a = 2 }) proc.call a CRYSTAL end it "can assign proc that returns anything to proc that returns nil (#3655)" do run(<<-CRYSTAL).to_i.should eq(2) class Foo @block : -> Nil def initialize(@block) end def call @block.call end end a = 1 block = ->{ a = 2 } Foo.new(block).call a CRYSTAL end it "can assign proc that returns anything to proc that returns nil, using union type (#3655)" do run(<<-CRYSTAL).to_i.should eq(3) class Foo @block : -> Nil def initialize(@block) end def call @block.call end end a = 1 block1 = ->{ a = 2 } block2 = ->{ a = 3; nil } Foo.new(block2 || block1).call a CRYSTAL end it "calls function pointer" do run(<<-CRYSTAL).to_i.should eq(2) require "prelude" fun foo(f : Int32 -> Int32) : Int32 f.call(1) end foo(->(x : Int32) { x &+ 1 }) CRYSTAL end it "casts from function pointer to proc" do codegen(<<-CRYSTAL) fun a(a : Void* -> Void*) Pointer(Proc((Void* -> Void*), Void*)).new(0_u64).value.call(a) end CRYSTAL end it "takes pointerof function pointer" do codegen(<<-CRYSTAL) fun a(a : Void* -> Void*) pointerof(a).value.call(Pointer(Void).new(0_u64)) end CRYSTAL end it "returns proc as function pointer inside top-level fun (#14691)" do run(<<-CRYSTAL, Int32).should eq(8) def raise(msg) while true end end fun add : Int32, Int32 -> Int32 ->(x : Int32, y : Int32) { x &+ y } end add.call(3, 5) CRYSTAL end it "returns ProcPointer inside top-level fun (#14691)" do run(<<-CRYSTAL, Int32).should eq(8) def raise(msg) while true end end fun foo(x : Int32) : Int32 x &+ 5 end fun bar : Int32 -> Int32 ->foo(Int32) end bar.call(3) CRYSTAL end it "raises if returning closure from top-level fun (#14691)" do run(<<-CRYSTAL).to_b.should be_true require "prelude" @[Raises] fun foo(x : Int32) : -> Int32 -> { x } end begin foo(1) rescue true else false end CRYSTAL end it "closures var on ->var.call (#8584)" do run(<<-CRYSTAL).to_i.should eq(1) def bar(x) x end struct Foo def initialize @value = 1 end def value bar(@value) @value end end def get_proc_a foo = Foo.new ->foo.value end def get_proc_b foo = Foo.new ->{ foo.value } end proc_a = get_proc_a proc_b = get_proc_b proc_b.call proc_a.call CRYSTAL end it "saves receiver value of proc pointer `->var.foo`" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize(@foo : Int32) end def foo @foo end end var = Foo.new(1) proc = ->var.foo var = Foo.new(2) proc.call CRYSTAL end it "saves receiver value of proc pointer `->@ivar.foo`" do run(<<-CRYSTAL).to_i.should eq(1) class Foo def initialize(@foo : Int32) end def foo @foo end end class Test @ivar = Foo.new(1) def test proc = ->@ivar.foo @ivar = Foo.new(2) proc.call end end Test.new.test CRYSTAL end it "saves receiver value of proc pointer `->@@cvar.foo`" do run(<<-CRYSTAL).to_i.should eq(1) require "prelude" class Foo def initialize(@foo : Int32) end def foo @foo end end class Test @@cvar = Foo.new(1) def self.test proc = ->@@cvar.foo @@cvar = Foo.new(2) proc.call end end Test.test CRYSTAL end it "doesn't crash when taking a proc pointer to a virtual type (#9823)" do run(<<-CRYSTAL, Proc(Int32, Int32, Int32)) abstract struct Parent abstract def work(a : Int32, b : Int32) def get ->work(Int32, Int32) end end struct Child1 < Parent def work(a : Int32, b : Int32) a &+ b end end struct Child2 < Parent def work(a : Int32, b : Int32) a &- b end end Child1.new.as(Parent).get CRYSTAL end it "doesn't crash when taking a proc pointer that multidispatches on the top-level (#3822)" do run(<<-CRYSTAL) class Foo def initialize(@proc : Proc(Bar, Nil)) end end module Bar end class Baz include Bar end def test(bar : Bar) if bar.is_a? Baz test bar end end def test(baz : Baz) end Foo.new(->test(Bar)) CRYSTAL end it "doesn't crash when taking a proc pointer that multidispatches on a module (#3822)" do run(<<-CRYSTAL) class Foo def initialize(@proc : Proc(Bar, Nil)) end end module Bar end class Baz include Bar end module Moo def self.test(bar : Bar) if bar.is_a? Baz test bar end end def self.test(baz : Baz) end end Foo.new(->Moo.test(Bar)) CRYSTAL end end