Newer
Older
Ary Borenszweig
committed
require "../../spec_helper"
describe "Code gen: fun" do
it "call simple fun literal" do
run("x = -> { 1 }; x.call").to_i.should eq(1)
end
it "call fun literal with arguments" do
run("f = ->(x : Int32) { x + 1 }; f.call(41)").to_i.should eq(42)
end
it "call fun pointer" do
run("def foo; 1; end; x = ->foo; x.call").to_i.should eq(1)
end
it "call fun pointer with args" do
run("
def foo(x, y)
x + y
end
f = ->foo(Int32, Int32)
f.call(1, 2)
").to_i.should eq(3)
end
Juan Wajnerman
committed
it "call fun pointer of instance method" do
run(%(
Ary Borenszweig
committed
class Foo
def initialize
@x = 1
end
def coco
@x
end
end
foo = Foo.new
f = ->foo.coco
f.call
Juan Wajnerman
committed
)).to_i.should eq(1)
Ary Borenszweig
committed
end
it "call fun pointer of instance method that raises" do
run(%(
require "prelude"
class Foo
def coco
raise "foo"
end
end
foo = Foo.new
f = ->foo.coco
f.call rescue 1
)).to_i.should eq(1)
end
Ary Borenszweig
committed
it "codegens fun with another var" do
run("
def foo(x)
bar(x, -> {})
end
def bar(x, proc)
end
foo(1)
")
end
it "codegens fun that returns a virtual type" do
run("
class Foo
def coco; 1; end
end
class Bar < Foo
def coco; 2; end
end
x = -> { Foo.new || Bar.new }
x.call.coco
").to_i.should eq(1)
end
Ary Borenszweig
committed
it "codegens fun that accepts a union and is called with a single type" do
run("
f = ->(x : Int32 | Float64) { x + 1 }
f.call(1).to_i
").to_i.should eq(2)
end
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
it "makes sure that fun pointer is transformed after type inference" do
run("
require \"prelude\"
class B
def initialize(@x)
end
def x
@x
end
end
class A
def on_something
B.new(1)
end
end
def _on_(p : A*)
p.value.on_something.x
end
c = ->_on_(A*)
a = A.new
c.call(pointerof(a))
").to_i.should eq(1)
end
it "binds function pointer to associated call" do
run("
class A
def initialize(@e : Int32)
end
def on_something
@e
end
end
def _on_(p : A*)
p.value.on_something
end
c = ->_on_(A*)
a = A.new(12)
a.on_something
c.call(pointerof(a))
").to_i.should eq(12)
end
it "call simple fun literal with return" do
run("x = -> { return 1 }; x.call").to_i.should eq(1)
end
it "calls fun pointer with union (passed by value) arg" do
run("
struct Number
def abs; self; end
end
f = ->(x : Int32 | Float64) { x.abs }
f.call(1 || 1.5).to_i
").to_i.should eq(1)
end
it "allows passing fun type to C automatically" do
run(%(
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.buffer as Void*), LibC::SizeT.cast(ary.length), LibC::SizeT.cast(sizeof(Int32)), ->(a : Void*, b : Void*) {
a = a as Int32*
b = b as Int32*
a.value <=> b.value
})
ary[0]
)).to_i.should eq(1)
end
it "allows fun pointer where self is a class" do
run("
class A
def self.bla
1
end
end
f = ->A.bla
f.call
").to_i.should eq(1)
end
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
it "codegens fun literal hard type inference (1)" do
run(%(
require "prelude"
class Foo
def initialize(@x)
end
def x
@x
end
end
def foo(s)
Foo.new(s.x)
end
def bar
->(s : Foo) { ->foo(Foo) }
end
bar
1
)).to_i.should eq(1)
end
it "automatically casts fun that returns something to fun that returns void" do
run("
$a = 0
def foo(x : ->)
x.call
end
foo ->{ $a = 1 }
$a
").to_i.should eq(1)
end
it "allows fun type of enum type" do
run("
enum MyEnum
X = 1
end
end
").to_i.should eq(1)
end
it "allows fun type of enum type with base type" do
run("
Ary Borenszweig
committed
enum MyEnum : UInt16
Ary Borenszweig
committed
it "codegens nilable fun type (1)" do
run("
a = 1 == 2 ? nil : ->{ 3 }
if a
a.call
else
4
end
").to_i.should eq(3)
end
it "codegens nilable fun type (2)" do
run("
a = 1 == 1 ? nil : ->{ 3 }
if a
a.call
else
4
end
").to_i.should eq(4)
end
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
it "codegens nilable fun type dispatch (1)" do
run("
def foo(x : -> U)
x.call
end
def foo(x : Nil)
0
end
a = 1 == 1 ? (->{ 3 }) : nil
foo(a)
").to_i.should eq(3)
end
it "codegens nilable fun type dispatch (2)" do
run("
def foo(x : -> U)
x.call
end
def foo(x : Nil)
0
end
a = 1 == 1 ? nil : ->{ 3 }
foo(a)
").to_i.should eq(0)
end
Ary Borenszweig
committed
it "builds fun type from fun" do
build("
Ary Borenszweig
committed
fun foo : ->
end
Ary Borenszweig
committed
x.call
")
end
it "builds nilable fun type from fun" do
build("
Ary Borenszweig
committed
fun foo : (->)?
end
Ary Borenszweig
committed
if x
x.call
end
")
end
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
it "assigns nil and fun to nilable fun type" do
run("
class Foo
def initialize
end
def x=(@x)
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
").to_i.should eq(1)
end
it "allows invoking fun literal with smaller type" do
run("
struct Nil
def to_i
0
end
end
f = ->(x : Int32 | Nil) {
x
}
f.call(1).to_i
").to_i.should eq(1)
end
Ary Borenszweig
committed
it "does closure? false" do
run("
->{ 1 }.closure?
").to_b.should be_false
end
it "does closure? false" do
run("
a = 1
->{ a }.closure?
").to_b.should be_true
end
it "does pointer" do
address = run("
->{}.pointer.address
").to_i
address.should be > 0
it "does new on fun type" do
run("
alias F = Int32 -> Int32
a = 2
f = F.new { |x| x + a }
f.call(1)
").to_i.should eq(3)
end
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
it "allows invoking a function with a subtype" do
run(%(
class Foo
def x
1
end
end
class Bar < Foo
def x
2
end
end
f = ->(foo : Foo) { foo.x }
f.call Bar.new
)).to_i.should eq(2)
end
it "allows invoking a function with a subtype when defined as block spec" do
run(%(
class Foo
def x
1
end
end
class Bar < Foo
def x
2
end
end
def func(&block : Foo -> U)
block
end
f = func { |foo| foo.x }
f.call Bar.new
)).to_i.should eq(2)
end
it "allows redefining fun" do
run(%(
fun foo : Int32
1
end
fun foo : Int32
2
end
foo
)).to_i.should eq(2)
end
Ary Borenszweig
committed
it "passes block to another function (bug: mangling of both methods was the same)" do
run(%(
def foo(&block : ->)
foo(block)
end
def foo(block)
1
end
foo { }
)).to_i.should eq(1)
end
it "codegens fun with union type that returns itself" do
run(%(
a = 1 || 1.5
foo = ->(x : Int32 | Float64) { x }
foo.call(a)
foo.call(a).to_i
)).to_i.should eq(1)
end
it "codegens issue with missing byval in fun literal inside struct" do
run(%(
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
)).to_string.should eq("bar")
end
Ary Borenszweig
committed
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
it "codegens fun that references struct (bug)" do
run(%(
class Context
def initialize
@x = Reference.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
)).to_i.should_not eq(42)
end
it "codegens captured block that returns tuple" do
build(%(
def foo(&block)
block
end
block = foo do
{0, 0, 42, 0}
end
block.call
))
end