# Package for Rust-like borrow checker in Julia?

**URL:** <https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442>\
**Category:** General Usage\
**Tags:** question\
**Created:** [January 5, 2025, 11:17am UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442 "2025-01-05T11:17:12Z")\
**Posts on this page:** 20\
**Page:** 4

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 7, 2025, 10:41am UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/61 "2025-01-07T10:41:17Z")

</div>

I think this is a really subtle design question that needs to look at the tradeoff between convenience and safety.

So, generally speaking, you can always `@take` an owned variable to unpack it, and ship that off to the external method. This trips the `.moved = true` so you can’t use the variable after that point. You would have to create a new owned variable, like

```julia
@own y = maybe_mutating_function!(@take x)

```

I think this design might be ok for many things. It’s quite similar to a lot of Rust code, when a variable’s ownership is lost. It also lets you gradually increase the number of functions with borrow checking, without forcing you to update your whole codebase at once.

Now, I’ve also written some of the methods needed for collections and math:

> <https://github.com/MilesCranmer/BorrowChecker.jl/blob/b177e88790121fbb70a65b257a50043bc9a5094d/src/overloads.jl#L47-L100>

We can probably add some other basic stuff. The main thing is to know when it’s okay to have `:write` versus `:read` in accesses as that determines what variable states are allowed when using them.

All other methods not provided here, the user would need to specify explicitly. I thought about having a special `BorrowedArray{T} <: AbstractArray{T} ` type for arrays, and another for `Number`, but I realised it is problematic to do this sort of thing implicitly.

In some sense, we actually **_want_** the MethodError, so that the user is forced to either `@take` the variable, or explicitly declare functions as being borrow-compatible.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 7, 2025, 11:02am UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/62 "2025-01-07T11:02:14Z")

</div>

One super tricky method is `iterate`. I haven’t defined that yet… not sure how. Should the default `iterate(x)` return references or owned values?

But if we return references, we’ll have to enforce that the user only uses `foreach(x) do ... end` so that we can constraint the lifetimes of the references.

If we return owned values, then the user can’t use the array after iterating over it.

(Speaking of which I should probably add a `@clone` that performs a move-free `@take` followed by deepcopy.)

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [January 7, 2025, 11:15am UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/63 "2025-01-07T11:15:59Z")

</div>

> [@MilesCranmer](#):
>
> `iterate(x)` return references or owned values?

If I’m understanding Rust correctly (I don’t in general), that’s up to the variable declaration if there is one, not the object `x.next()` returns.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 7, 2025, 12:00pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/64 "2025-01-07T12:00:57Z")

</div>

Yeah in Rust it is either:

```rust
let mut x = vec![1, 2, 3];

for xi in x {
    // xi is i32
    // Can't access x[0] here
}
// x no longer available!

/// OR

let mut x = vec![1, 2, 3];
for xi in &x {
    // xi is &i32
    // Can also use println!("{}", x[0]); - another immutable reference
}
// x available again!

/// OR

for xi in &mut x {
    // xi is &mut i32
    // Can change xi if we want
    // However, we CANT access x[0] here
}

```

So I guess my question is, do we want `iterate(x)` to generate `Borrowed{T}` of elements, or `Owned{T}` of elements? As you can see there are various tradeoffs here.

Maybe `Owned{T}` is best here by default, since you could get the 2nd format above with a `@lifetime` block again:

```julia
@own x = [MyMutable(1), MyMutable(2)]

@lifetime lt begin
    @own const rx = x in lt
    for xi in rx
        xi::Borrowed{T}
        # CANT edit
        # but we CAN get x[1] here (another Borrowed{T})
    end
end
# x is still available

@lifetime lt begin
    @own rx = x in lt
    for xi in rx
        xi::BorrowedMut{T}
        # CAN edit xi
        # but we CANT access x[1]
    end
end
# x is still available

for xi in x
    xi::OwnedMut{T}
    # Can edit xi
end
# However, now x is no longer available! It was moved!

```

What do you think?

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 7, 2025, 12:31pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/65 "2025-01-07T12:31:59Z")

</div>

@Benny Ok I got the above idea working for `Borrowed` (i.e., `@ref const rx = x in lt`). iterating over `Owned*` or `BorrowedMut` is going to need a redesign though!

> <https://github.com/MilesCranmer/BorrowChecker.jl/blob/ee302378e6fc1de36d605cbba97232c43fd956c3/src/overloads.jl#L79-L84>

This now works:

```julia
@own x = [1, 2, 3]
@lifetime lt begin
    @ref const ref = x in lt
    for (i, xi) in enumerate(ref)
        @test xi isa Borrowed{Int}
        @test xi == x[i]
    end
end

```

It would be nice to something like the following syntax; but sadly it it doesn’t work.

```julia
julia> ex = quote
           for const xi in x
ERROR: ParseError:
#= Error @ REPL[1]:2:9
ex = quote
    for const xi in x
# └───────────┘ ── expected assignment after `const` =#

julia> ex = quote
           for const xi = x
           end
       end
ERROR: ParseError:
#= Error @ REPL[2]:2:21
ex = quote
    for const xi = x
# └ ── invalid iteration spec: expected one of `=` `in` or `∈` =#

```

* * *

P.S., after staring at `@own const x = [1, 2, 3]` for a while I’m not sure I like it. Any ideas for alternative syntaxes?

Random ideas:

```julia
# immutable # mutable
@own const x = [1, 2, 3]; @own y = [1, 2, 3];

# Separate macros
@own x = [1, 2, 3]; @own_mut y = [1, 2, 3];
@let x = [1, 2, 3]; @let_mut y = [1, 2, 3]; # actual rust syntax; but bad Julia intuition
@const x = [1, 2, 3]; @mut y = [1, 2, 3];
@freeze x = [1, 2, 3]; @melt y = [1, 2, 3];

# Annotation
@own x = [1, 2, 3]; @own y::mut = [1, 2, 3];
@own x = [1, 2, 3]; @own y::(@mut) = [1, 2, 3];

# Macro option
@own x = [1, 2, 3]; @own :mut y = [1, 2, 3];

# Chained macros
@own x = [1, 2, 3]; @own @mut y = [1, 2, 3];

```

Then, what word? `@own`, `@track`, `@safe`, `@let`? Maybe `@bind`?

I do think it’s better to have the immutable syntax be easier, as a way to encourage its more frequent use.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [January 7, 2025, 5:12pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/66 "2025-01-07T17:12:14Z")

</div>

I mean, the core challenge is that you’re trying to track references and borrows thereof in a language that simply _doesn’t use any notion of first-class references_. So you have to introduce the references — those wrappers — for _everything_, and then you have to change what assignment means, and then you need to think about what function calls mean.

In general, trying to forward methods through wrappers is quite fraught, especially when you start trying to put those wrappers inside structs, containers, and other data structures.

I do appreciate your tenacity though. At the risk of suggesting something **terribly cursed** , has anyone ever tried doing the Ruby monkey-patch thing of redirecting `method_missing` to do the unwrap-and-forward step with `MethodError`s (or somewhere else in the system) in Julia? An optional checker system like this actually seems like a somewhat defensible use of the technique… if it’s possible at all. I’m thinking it’s probably not possible, though.

Edit: Actually, this is very Cassette.jl ish.

---

<div class="post-metadata">

**Author:** ![mrufsvold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrufsvold/32/31600_2.png) [@mrufsvold](https://discourse.julialang.org/u/mrufsvold)\
**Post date:** [January 7, 2025, 5:23pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/67 "2025-01-07T17:23:56Z")

</div>

> [@MilesCranmer](#):
>
> This actually works with the current API. The new `x` would just be a regular `Int` (we can’t override assignment in Julia). But we really really want to discourage it, since it breaks this simulated borrow checker.

I only had time to skim the rest of this so I’m sorry if this was addressed, but while you can’t override assignment, couldn’t you use `@borrow_checker` to require all instances of `Expr(:(=), ...)` to include one of your assignment macros?

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 7, 2025, 5:39pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/68 "2025-01-07T17:39:31Z")

</div>

> [@mbauman](#):
>
> I mean, the core challenge is that you’re trying to track references and borrows thereof in a language that simply _doesn’t use any notion of first-class references_. So you have to introduce the references — those wrappers — for _everything_, and then you have to change what assignment means, and then you need to think about what function calls mean.

If we want the same language-wide logical guarantees as rust, then I agree, it is probably impossible. But if we just want to incrementally improve the design of some library, we can work from inside-out, and do a `@take` whenever one hits the limits of the methods that have started to use it.

Also, not my first rodeo! DispatchDoctor.jl does the analogous thing but for static return typing 😃 It’s far from comprehensive (see list of caveats at the end, not to mention completely ignoring internal instabilities) but it has caught so so soooo many unintentional type instabilities for me, that it has become an absolutely essential piece of my toolbox.

DispatchDoctor.jl is imperfect, and goes against some of the original design of the language, and does not cover “_everything_,” but at the same time, it’s really useful! I think the same thing would be true of a pseudo-borrow checker.

> [@mbauman](#):
>
> Ruby monkey-patch thing of redirecting `method_missing` to do the unwrap-and-forward step with `MethodError`s

Sounds super cool indeed. Especially if BorrowChecker.jl is only meant to be a tool for test/develop time, I feel like monkey patching is far more acceptable. And it could be yet another thing controlled by Preferences.jl

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 7, 2025, 5:49pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/69 "2025-01-07T17:49:45Z")

</div>

Possibly. Right now what I do is just store the symbol in the struct

```julia
mutable struct Bound{T}
    const value::T
    @atomic moved::Bool
    @atomic immutable_borrows::Int
    const symbol::Symbol
    const threadid::Int
end

```

(used to be named `Owned`; sorry, I’m still fiddling with the API before it hits 0.1.)

This helps make sure you don’t cheat the system and use regular assignment, by storing the original variable _symbol_ into the object itself:

```julia
julia> @bind x = 1
Bound{Int64}(1)

julia> y = x
Bound{Int64}(1)

julia> @move z = y
ERROR: Variable `y` holds an object that was reassigned from `x`.

```

It does something similar with `Threads.threadid()`, so that you don’t try to pass a bound variable to a closure-based `Threads.@spawn` or something. You have to explicitly `@take`, `@clone`, or pass an immutable `@ref` there!

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 7, 2025, 6:37pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/70 "2025-01-07T18:37:14Z")

</div>

Btw @mbauman do you know if there are any new features I should be aware of regarding _ **aliasing detection** _? I took a look at [What's the aliasing story in Julia](https://discourse.julialang.org/t/whats-the-aliasing-story-in-julia/102564).

The reason I’m interested in it is because Rust has this feature of allowing multiple mutable references to an object if they point at _non-overlapping fields_. However, this is only safe because the compiler can prove whether fields are aliased or not.

Meaning this would work –

```julia
struct Point
    x::Vector{Int}
    y::Vector{Int}
end

# Mutable binding of a Point object
@bind @mut p = Point([1], [2])

@lifetime lt begin
    # Get references to all fields we'll need
    @ref @mut p_x = p.x in lt
    @ref @mut p_y = p.y in lt
end

```

These are mutable references (like C pointers) to `p.x` and `p.y`. In Rust, this is allowed, because the compiler can prove whether `x` and `y` are aliased or not (for any type of data structure). But in Julia I’m not sure if this is possible?

If not then I think we should just ban multiple mutable references (= current behavior), even if they refer to distinct fields. I think it just violates some of the borrow checker semantics. So we’ll be a bit stricter than Rust in that sense, only because we can’t prove things about the memory layout.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [January 7, 2025, 7:01pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/71 "2025-01-07T19:01:22Z")

</div>

> [@MilesCranmer](#):
>
> However, this is only safe because the compiler can prove whether fields are aliased or not.

Isn’t that “just” more borrow checking at work? Maybe that’s pedantic, but fundamentally it really shouldn’t matter whether your objects come from fields of the same struct or different ones or even different local “variable” references, should it? They’re all just references, and if they’re distinct then it’s ok. The fact that it’s not aliased just “falls out” of the enforcement of the borrow-checking rules, right?

Julia’s alias detection is far less definitive and much more rudimentary.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 7, 2025, 7:26pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/72 "2025-01-07T19:26:24Z")

</div>

Yeah I think you’re right. I guess in my head I was assuming that objects being passed into `@bind` might be unsafe due to being created outside of the borrow checker. But if you did create it within the framework, then I think (?) you are correct?

e.g., if I pass in data from the “real world” to the following function:

```julia
function foo(x::Array, y::Array)
    @bind @mut z = (x, y)

    @lifetime lt begin
        @ref @mut rx = z[1] in lt
        @ref @mut ry = z[2] in lt

        push!(ry, 2)
    end
end

```

with

```julia
julia> c = [1, 2, 3];

julia> foo(c, c) # aliased input => breaks multiple mut ref assumption

```

But if we had tried to start this using BorrowChecker.jl, we’d get an error:

```julia
julia> @bind c = [1, 2, 3];

julia> foo(@take(c), @take(c))
ERROR: Cannot use c: value has been moved

```

So it’s only as safe as the inputs. Maybe that’s the best we can do and I’m being overkill here? Ugh. Maybe the rules need to be configurable too…

(P.S., for monkey patching, I think `method_missing` could try calling `@take` on any `Bound` objects. That’s kinda getting the right behavior - then a user also can’t cheat and do `c1 = @take(c); foo(c1, c1)`)

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [January 7, 2025, 7:30pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/73 "2025-01-07T19:30:40Z")

</div>

> [@MilesCranmer](#):
>
> However, this is only safe because the compiler can prove whether fields are aliased or not.

> [@MilesCranmer](#):
>
> But in Julia I’m not sure if this is possible?

If it’s statically knowable like literal/constant fields then it should be possible. `Base.mightalias` works on a lot of `AbstractArray`s where the information for aliasing is only known at runtime. For example, `view(x, 1:2:9)` and `view(x, 2:2:10)` heavily imply they don’t alias, which `mightalias` detects, but they share the same `SubArray` type, so the compiler can’t even begin to tell. Even if `1:2:9` and `2:2:10` were constants, the compiler can’t immediately tell that they are indices that don’t alias; maybe `x`’s type is weird and only has 1 actual element.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 7, 2025, 7:54pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/74 "2025-01-07T19:54:25Z")

</div>

> [@mbauman](#):
>
> Edit: Actually, this is very [Cassette.jl](https://juliaregistries.github.io/General/packages/redirect_to_repo/Cassette) ish.

I think this could actually be the _proper_ way to pull this off? It looks perfect.

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [January 7, 2025, 8:20pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/75 "2025-01-07T20:20:00Z")

</div>

Would the newer compiler plugin interface be preferred these days over using Cassette.jl?

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 7, 2025, 8:23pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/76 "2025-01-07T20:23:59Z")

</div>

Is there an equivalent of `Cassette.overdub` in the new interface?

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [January 7, 2025, 8:34pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/77 "2025-01-07T20:34:53Z")

</div>

(I don’t know. That question was for someone more knowledgeable than me. 🙂)

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 7, 2025, 9:42pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/78 "2025-01-07T21:42:01Z")

</div>

@mbauman nice recommendation – it works!! Check this out:

```julia
julia> using BorrowChecker

julia> @bind x = 1
Bound{Int64}(1)

julia> f(x::Int) = x^2
f (generic function with 1 method)

julia> result = BorrowChecker.managed() do
           # Enters Cassette.@overdub context
           f(x)
       end
1

julia> x # Successfully moved
[moved]

```

It succesfully called `@take(x)` on our bound variable `x` despite us not doing anything.

The code was surprisingly concise too:

```julia
maybe_take!(x) = x
function maybe_take!(arg::AllBound)
    is_moved(arg) && throw(MovedError(arg.symbol))
    value = unsafe_get_value(arg)
    mark_moved!(arg)
    return value
end
const SKIP_METHODS = (
    Base.getindex, Base.setindex!, Base.getproperty,
    Base.setproperty!, Base.getfield, Base.setfield!
)
function skip_method(f)
    parentmodule(parentmodule(f)) == parentmodule(@ __MODULE__ ) || f in SKIP_METHODS
end

Cassette.@context ManagedCtx

function Cassette.overdub(ctx::ManagedCtx, f, args...)
    if skip_method(f)
        Cassette.fallback(ctx, f, args...)
    else
        Cassette.recurse(ctx, f, map(maybe_take!, args)...)
    end
end
function managed(f)
    Cassette.@overdub(Cassette.disablehooks(ManagedCtx()), f())
end

```

That’s it!!

All it does is: goes through the arguments of EVERY SINGLE external function call, run `maybe_take!` on the arguments, and then call the function. This results in all `Bound` and `BoundMut` objects being taken, which voids their ownership in their original scope, thus

```julia
julia> x == 2
ERROR: Cannot use x: value has been moved

```

i.e., it is no longer owned, and can’t be used!

The only functions where `x` won’t be taken are ones we have defined explicitly. Otherwise we assume all external functions take ownership unless specified otherwise.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [January 7, 2025, 10:47pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/79 "2025-01-07T22:47:12Z")

</div>

Of course now the trouble is that Cassette doesn’t work on 1.12, and I’m similarly out of touch on what’s happening in this space. But yes, I suspect this sort of approach will work much better.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 7, 2025, 11:35pm UTC](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442/80 "2025-01-07T23:35:00Z")

</div>

Weird, it still works for me on nightly.

[Make `import Cassette` work on Julia 1.12 (although the package proba… · JuliaLabs/Cassette.jl@7e798c2 · GitHub](https://github.com/JuliaLabs/Cassette.jl/commit/7e798c227d5aefd70c8174992a629422d70fae7b) – I guess I just haven’t hit a code path that used this removed bit yet??

* * *

Edit: nevermind, while the unittest work on 1.12, the REPL attempt fails:

```julia
julia> BorrowChecker.managed() do
           foo(x)
       end
ERROR: The function body AST defined by this @generated function is not pure. This likely means it contains a closure, a comprehension or a generator.

```

[Previous page](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442.md?page=3)

[Next page](https://discourse.julialang.org/t/package-for-rust-like-borrow-checker-in-julia/124442.md?page=5)
