Skip to content

Commit cfb7402

Browse files
committed
Expand to cover positional args as well
1 parent 429b131 commit cfb7402

File tree

3 files changed

+65
-7
lines changed

3 files changed

+65
-7
lines changed

docs/src/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,5 @@ An opt-in mechanism marks functions that might contain `Libtask.produce` stateme
2828

2929
```@docs; canonical=true
3030
Libtask.might_produce(::Type{<:Tuple})
31-
Libtask.@might_produce_kwargs
31+
Libtask.@might_produce
3232
```

src/copyable_task.jl

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -360,11 +360,12 @@ that, by default, we assume that calls do not contain `Libtask.produce` statemen
360360
might_produce(::Type{<:Tuple}) = false
361361

362362
"""
363-
@might_produce_kwargs(f)
363+
@might_produce(f)
364364
365-
If `f` is a function that has keyword arguments and may call `Libtask.produce` inside it,
366-
then `@might_produce_kwargs(f)` will generate the appropriate methods needed to ensure that
367-
`Libtask.might_produce` returns `true` for the relevant signatures of `f`.
365+
If `f` is a function that may call `Libtask.produce` inside it, then `@might_produce(f)`
366+
will generate the appropriate methods needed to ensure that `Libtask.might_produce` returns
367+
`true` for all relevant signatures of `f`. This works even if `f` has methods with keyword
368+
arguments.
368369
369370
```jldoctest kwargs
370371
julia> # For this demonstration we need to mark `g` as not being inlineable.
@@ -381,15 +382,18 @@ f (generic function with 1 method)
381382
julia> # This returns nothing because `g` isn't yet marked as being able to `produce`.
382383
consume(Libtask.TapedTask(nothing, f))
383384
384-
julia> Libtask.@might_produce_kwargs(g)
385+
julia> Libtask.@might_produce(g)
385386
386387
julia> # Now it works!
387388
consume(Libtask.TapedTask(nothing, f))
388389
6
389390
"""
390-
macro might_produce_kwargs(f)
391+
macro might_produce(f)
391392
# See https://github.com/TuringLang/Libtask.jl/issues/197 for discussion of this macro.
392393
quote
394+
function $(Libtask).might_produce(::Type{<:Tuple{typeof($(esc(f))),Vararg}})
395+
return true
396+
end
393397
possible_n_kwargs = unique(map(length Base.kwarg_decl, methods($(esc(f)))))
394398
if possible_n_kwargs != [0]
395399
# Oddly we need to interpolate the module and not the function: either

test/copyable_task.jl

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
module Functions
2+
using Libtask: produce
3+
@noinline g3(x) = produce(x)
4+
@noinline g3(x, y; z) = produce(x + y + z)
5+
@noinline g3(x, y, z; p, q) = produce(x + y + z + p + q)
6+
function f3(x)
7+
g3(x)
8+
g3(x, 1; z=2)
9+
g3(x, 1, 2; p=3, q=4)
10+
end
11+
end
12+
113
@testset "copyable_task" begin
214
for case in Libtask.TestUtils.test_cases()
315
case()
@@ -251,4 +263,46 @@
251263
@test Libtask.consume(tt) === :a
252264
@test Libtask.consume(tt) === nothing
253265
end
266+
267+
@testset "@might_produce macro" begin
268+
# Positional arguments only
269+
@noinline g1(x) = produce(x)
270+
f1(x) = g1(x)
271+
# Without marking it as might_produce
272+
tt = Libtask.TapedTask(nothing, f1, 0)
273+
@test Libtask.consume(tt) === nothing
274+
# Now marking it
275+
Libtask.@might_produce(g1)
276+
tt = Libtask.TapedTask(nothing, f1, 0)
277+
@test Libtask.consume(tt) === 0
278+
@test Libtask.consume(tt) === nothing
279+
280+
# Keyword arguments only
281+
@noinline g2(x; y=1, z=2) = produce(x + y + z)
282+
f2(x) = g2(x)
283+
# Without marking it as might_produce
284+
tt = Libtask.TapedTask(nothing, f2, 0)
285+
@test Libtask.consume(tt) === nothing
286+
# Now marking it
287+
Libtask.@might_produce(g2)
288+
tt = Libtask.TapedTask(nothing, f2, 0)
289+
@test Libtask.consume(tt) === 3
290+
@test Libtask.consume(tt) === nothing
291+
292+
# A function with multiple methods.
293+
# Note: f3 and g3 are defined in the module at the top of this file. If
294+
# they are defined directly in this testset, for reasons that are
295+
# unclear, the `produce` calls are picked up even without using the
296+
# `@might_produce` macro, meaning that it's impossible to test that the
297+
# macro is having the intended behaviour.
298+
tt = Libtask.TapedTask(nothing, Functions.f3, 0)
299+
@test Libtask.consume(tt) === nothing
300+
# Now marking it
301+
Libtask.@might_produce(Functions.g3)
302+
tt = Libtask.TapedTask(nothing, Functions.f3, 0)
303+
@test Libtask.consume(tt) === 0
304+
@test Libtask.consume(tt) === 3
305+
@test Libtask.consume(tt) === 10
306+
@test Libtask.consume(tt) === nothing
307+
end
254308
end

0 commit comments

Comments
 (0)