Blacklisting a type from being captured in functions

:mega: WHERE THERE’S A WILL, THERE’S A WAY!!

Check this out. BorrowChecker.jl now uses Cassette.jl to overdub Core.setfield!(::Core.Box, :contents, ...) so that if you try to capture any Bound variable in a closure, an error will be thrown:

julia> using BorrowChecker

julia> function f()
           @bind x = 1
           function g()
               x = x + 1
           end
           g()
           return x
       end
f (generic function with 1 method)

julia> BorrowChecker.@managed begin
           f()
       end
ERROR: You are not allowed to capture bound variable `x` inside a closure.
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:35

Works like this:

function Cassette.overdub(ctx::ManagedCtx, f, args...)
    if f == Core.setfield! &&
        length(args) == 3 &&
        args[1] isa Core.Box &&
        args[2] == :contents &&
        args[3] isa Union{Bound,BoundMut}

        symbol = args[3].symbol
        error("You are not allowed to capture bound variable `$(symbol)` inside a closure.")
    end
    #= Other overdubbing =#
end

(And before anybody says “this is hacky, don’t do this, etc.”, yes, I know. BorrowChecker.jl is not going to be standard Julia code. That’s ok though, because it’s just a debugging tool!)

3 Likes