<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>verdagon.dev</title>
  <subtitle>Browse aymeric&#39;s, an independent, searchable archive of readable snapshots from followed feeds, preserved in Git with aggr.</subtitle>
  <id>https://aggr.aymericbeaumet.com/sources/verdagon.dev/</id>
  <link rel="alternate" type="text/html" href="https://aggr.aymericbeaumet.com/sources/verdagon.dev/"/>
  <link rel="self" type="application/atom+xml" href="https://aggr.aymericbeaumet.com/sources/verdagon.dev/atom.xml"/>
  <updated>2026-10-18T12:11:13+00:00</updated>
  <author>
    <name>aymeric&#39;s</name>
  </author>
  <generator version="2.0.0" uri="https://github.com/aymericbeaumet/aggr">aggr</generator>
  <entry>
    <id>urn:aggr:item:26b708ed41c57bc956662f5f3f06c34009a606d0</id>
    <title type="text">A new way to think about borrow checking (in reverse)</title>
    <link rel="alternate" type="text/html" href="https://aggr.aymericbeaumet.com/items/hnrss-org/2026-10-18-a-new-way-to-think-about-borrow-checking-in-reverse/"/>
    <link rel="via" type="text/html" href="https://verdagon.dev/blog/reverse-borrow-checking"/>
    <published>2026-10-18T12:11:13+00:00</published>
    <updated>2026-10-18T12:11:13+00:00</updated>
    <author>
      <name>verdagon</name>
    </author>
    <category term="news"/>
    <source>
      <title>Hacker News: Front Page</title>
    </source>
    <summary type="text">Travel backwards in time, so that you already know the future Oct 18, 2026 — Have you ever had a weird idea, and then it worked, but you can&#39;t really believe it? That&#39;s what I&#39;m feeling right now, about Valen&#39;s borrow checker. Because it…</summary>
    <content type="html">&lt;p&gt;Travel backwards in time, so that you already know the future&lt;/p&gt;
&lt;p&gt;Oct 18, 2026  —&lt;/p&gt;
&lt;p&gt;Have you ever had a weird idea, and then it worked, but you can&#39;t really believe it?&lt;/p&gt;
&lt;p&gt;That&#39;s what I&#39;m feeling right now, about Valen&#39;s borrow checker.&lt;/p&gt;
&lt;p&gt;Because it &lt;strong&gt;travels backward through time.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Or, to be less dramatic, it &lt;strong&gt;walks functions backwards,&lt;/strong&gt; which is still &lt;em&gt;very&lt;/em&gt; weird.&lt;/p&gt;
&lt;p&gt;Years ago, if you told me it would be good to iterate a function in reverse, I would have called you crazy.&lt;/p&gt;
&lt;p&gt;It turns out, there&#39;s actually some really good reasons to do this, and it&#39;s fairly common when you&#39;re doing e.g. optimization passes. &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn-1&quot; id=&quot;fnref-1&quot; data-footnote-ref&gt;1&lt;/a&gt;&lt;/sup&gt; But I don&#39;t think anyone&#39;s done this for checking memory safety.&lt;/p&gt;
&lt;p&gt;If you want a really deep look into the world of borrow checking, read on!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We&#39;re about to see some weird things.&lt;/em&gt; &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;#fn-2&quot; id=&quot;fnref-2&quot; data-footnote-ref&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;This is a pretty deep under-the-hood look into borrow checking algorithms. If you want something epic and entertaining instead, check out my recent post on &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/golden-spike-reviving-vale-valen&quot;&gt;The Golden Spike, and Resurrecting the Vale(n) Programming Language&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;A weird kind of borrow checker&lt;/h2&gt;
&lt;p&gt;This isn&#39;t going to be your normal shared-xor-mutable borrow checking.&lt;/p&gt;
&lt;p&gt;This is &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://github.com/valen-lang/valen&quot;&gt;Valen&lt;/a&gt;&#39;s borrow checker, the one that &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/valen-group-borrowing&quot;&gt;makes shared-xor-mutable optional&lt;/a&gt;, and can &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/golden-spike-reviving-vale-valen&quot;&gt;call into Rust functions&lt;/a&gt; with &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/boundary-memory-safety&quot;&gt;memory safety across the boundary&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Valen is still very experimental. Many things have holes and sharp edges, and likely will until v0.1 comes sometime in February. The glorious months-long refactoring spree is already underway (hence this new borrow checker!). Feel free to check out the &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://github.com/valen-lang/valen&quot;&gt;Valen repo&lt;/a&gt; and beware, here be dragons! &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/reverse-borrow-checking#note2&quot;&gt;2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It&#39;s kind of like Rust&#39;s borrow checker, but it also has memory-safe mutable aliasing. If you want to know more about that, check out &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/valen-group-borrowing&quot;&gt;this post&lt;/a&gt;, though you won&#39;t need to understand that for most of this post.&lt;/p&gt;
&lt;p&gt;2&lt;/p&gt;
&lt;p&gt;Green dragons, specifically.&lt;/p&gt;
&lt;h2&gt;...and a weird, backwards implementation!&lt;/h2&gt;
&lt;p&gt;Valen compiles a function in four phases: &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/reverse-borrow-checking#note3&quot;&gt;3&lt;/a&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It &lt;strong&gt;parses&lt;/strong&gt; the function, turning source text into an AST.&lt;/li&gt;
&lt;li&gt;It does &lt;strong&gt;static typing&lt;/strong&gt;, figuring out the type for every variable, argument, and expression.&lt;/li&gt;
&lt;li&gt;It does &lt;strong&gt;static grouping&lt;/strong&gt;, where every reference knows &lt;strong&gt;what variable&lt;/strong&gt; (or what &lt;em&gt;part&lt;/em&gt; of what variable) it&#39;s pointing at. &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/reverse-borrow-checking#note4&quot;&gt;4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;It &lt;strong&gt;safety-checks&lt;/strong&gt; the function, to make sure that a reference isn&#39;t used after it&#39;s invalidated.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I&#39;ll explain all of this further below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The weirdest part is that #4 happens in reverse.&lt;/strong&gt; It looks at the last statement in the function, and then walks backwards until it reaches the top of the function.&lt;/p&gt;
&lt;p&gt;This is weird because, as far as I know, it&#39;s the &lt;strong&gt;only borrow checker whose safety check goes backwards.&lt;/strong&gt; &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/reverse-borrow-checking#note5&quot;&gt;5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Further below, I&#39;ll explain why we&#39;re going backwards (hint: convenience, loops, and speed).&lt;/p&gt;
&lt;p&gt;But first, let&#39;s see &lt;strong&gt;how it works,&lt;/strong&gt; and what it even &lt;em&gt;means&lt;/em&gt; to go backwards.&lt;/p&gt;
&lt;p&gt;Let&#39;s skip phase 1, and start with phase 2.&lt;/p&gt;
&lt;p&gt;3&lt;/p&gt;
&lt;p&gt;There&#39;s also a secret fifth phase, where we calculate what attributes to send to LLVM to describe what operations might change what groups. But that&#39;s out of scope for this article.&lt;/p&gt;
&lt;p&gt;4&lt;/p&gt;
&lt;p&gt;It also figures out all the groups invalidated by any mut effects from any instructions.&lt;/p&gt;
&lt;p&gt;5&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rust (NLL and the current Polonius) does a constraint-solve for region inference, then a &lt;strong&gt;forward&lt;/strong&gt; pass to check for conflicts. (Note that rustc does do a backwards scan to figure out where each variable is used, but its actual memory safety checks happen in a forward pass.)&lt;/li&gt;
&lt;li&gt;Vale&#39;s typing pass determines regions, then a later &lt;strong&gt;forward&lt;/strong&gt; pass does &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/zero-cost-borrowing-regions-part-1-immutable-borrowing&quot;&gt;region borrow checking&lt;/a&gt; to determine when it can safely skip run-time &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/generational-references&quot;&gt;generation checks&lt;/a&gt;. (Vale&#39;s region borrow checker was actually fused with its instantiator/monomorphizer.)&lt;/li&gt;
&lt;li&gt;Valen&#39;s previous borrow checker did it like Vale too; its typing pass determines groups, then a later &lt;strong&gt;forward&lt;/strong&gt; pass would check at every use that it was declared more recently than it was &amp;quot;invalidated&amp;quot;.&lt;/li&gt;
&lt;li&gt;There are a lot of other borrow checkers out there, but I haven&#39;t heard of any doing their safety checks in reverse. If anyone knows of any, let me know!&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Phase 2: Static Typing&lt;/h3&gt;
&lt;p&gt;The static typing pass will be familiar to some of you, it assigns types to variables.&lt;/p&gt;
&lt;p&gt;For example, it turns this program:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;exported func main() {
  let fuel = 5;
  let force = fuel;
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;into this program:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;exported func main() {
  let fuel i64 = 5;
  let force i64 = fuel;
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is pretty normal, lots of compilers do it.&lt;/p&gt;
&lt;p&gt;Compilers usually do this as a &lt;strong&gt;forward&lt;/strong&gt; pass, walking from the top of the function to the bottom, figuring out types as it goes.&lt;/p&gt;
&lt;p&gt;We&#39;re going to do something &lt;em&gt;similar but weirder&lt;/em&gt; in phase 3; phase 3 is going to do &lt;strong&gt;static grouping.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Phase 3: Static Grouping &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/reverse-borrow-checking#note6&quot;&gt;6&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is another forward pass, which figures out where each reference points to.&lt;/p&gt;
&lt;p&gt;For example, in this program:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;func print_first_fuel_cell(s &amp;amp;Ship) {
  let first_ref = &amp;amp;s.fuel_cells[0];
  print_int(first_ref);
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Static grouping figures out that first_ref is pointing in s.fuel_cells[]: &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/reverse-borrow-checking#note7&quot;&gt;7&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;func print_first_fuel_cell(s &amp;amp;Ship) {
  // Static typing says:   first_ref &amp;amp;int
  // Static grouping says: first_ref &amp;amp;int in s.fuel_cells[]
  let first_ref = &amp;amp;s.fuel_cells[0];
  print_int(first_ref);
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other words, it&#39;s pointing to an int somewhere in the s.fuel_cells[] array.&lt;/p&gt;
&lt;p&gt;This information is now &lt;em&gt;part of the variable&#39;s type.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We&#39;ll be using this information in the next phase, which actually checks for use-after-free.&lt;/p&gt;
&lt;p&gt;6&lt;/p&gt;
&lt;p&gt;I&#39;ll probably start moving away from the term &amp;quot;group&amp;quot; soon, switching to &amp;quot;path&amp;quot; instead. Opinions welcome!&lt;/p&gt;
&lt;p&gt;7&lt;/p&gt;
&lt;p&gt;In V1&#39;s static grouping phase, it would also figure out &lt;em&gt;when&lt;/em&gt; a reference was made. So for example, instead of &amp;amp;int in s.fuel_cells[], it would know that it was &amp;amp;int in s.fuel_cells[] from line 7.2. This was pretty awesome, we were literally &lt;strong&gt;smuggling time and space&lt;/strong&gt; information into a variable&#39;s type. This new V2 version doesn&#39;t need to do that because it does a backwards scan, as we&#39;ll see next.&lt;/p&gt;
&lt;h3&gt;Phase 4: Safety Checking&lt;/h3&gt;
&lt;p&gt;This post is half for fun, but also to &lt;strong&gt;ask for feedback on the algorithm.&lt;/strong&gt; I don&#39;t think anyone&#39;s done it this way before, and there might be a good reason for that. If you see any problems with this approach, please help me out by &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://www.reddit.com/r/Valen/comments/1x92s1o/a_new_way_to_think_about_borrow_checking_in/&quot;&gt;leaving a comment&lt;/a&gt;, so I can fix (or scrap!) the approach. &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/reverse-borrow-checking#note8&quot;&gt;8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now we can use everything Phase 3 calculated!&lt;/p&gt;
&lt;p&gt;This is the phase that &lt;strong&gt;checks for use-after-free.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It does it with a &lt;strong&gt;backwards scan,&lt;/strong&gt; &lt;em&gt;as was foretold.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Let&#39;s see it happen in a slightly bigger example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;struct Entity { hp int; buffs []int; }
func add_buff(self &amp;amp;Entity mut) { ... }

func foo(e &amp;amp;Entity mut) {
  let buff = &amp;amp;e.buffs[0];
  e.add_buff();
  print_int(buff);
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This program is doing a &lt;strong&gt;use after free,&lt;/strong&gt; and we want the compiler to complain.&lt;/p&gt;
&lt;p&gt;First, I&#39;ll desugar it into a more explicit syntax:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;struct Entity { hp int; buffs []int; }
func add_buff&amp;lt;g&amp;#39;&amp;gt;(self &amp;amp;Entity in g) mut(g) { ... }

func foo&amp;lt;g&amp;#39;&amp;gt;(e &amp;amp;Entity in g) mut(g) {
  let buff = &amp;amp;e.buffs[0];
  e.add_buff();
  print_int(buff);
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I&#39;m going to add in some comments, all determined by the backwards scan as it goes.&lt;/p&gt;
&lt;p&gt;Further below, I&#39;ll explain what &amp;quot;DECLARE&amp;quot;, &amp;quot;USE&amp;quot;, and &amp;quot;MUTATE&amp;quot; mean.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;struct Entity { hp int; buffs []int; }
func add_buff&amp;lt;g&amp;#39;&amp;gt;(self &amp;amp;Entity in g) mut(g) { ... }

func foo&amp;lt;g&amp;#39;&amp;gt;(
  e &amp;amp;Entity in g          // DECLARE e (group g)
) mut(g) {
  let buff = &amp;amp;e.buffs[0]; // DECLARE buff (group g.buffs[])
  e.add_buff();           // USE e (group g)
                          // MUTATE group g
  print_int(buff);        // USE buff (group g.buffs[])
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The algorithm walks &lt;strong&gt;in reverse,&lt;/strong&gt; from the end of the function to the start.&lt;/p&gt;
&lt;p&gt;As it scans upward, it looks for these events:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When we USE a variable, &lt;strong&gt;add&lt;/strong&gt; it to the pending list.&lt;/li&gt;
&lt;li&gt;When we MUTATE anything, ensure no variables in pending are invalidated.&lt;/li&gt;
&lt;li&gt;When we DECLARE a variable, &lt;strong&gt;remove&lt;/strong&gt; it from the pending list.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;pending contains all of the things USEd below, that we hope to see DECLAREd above.&lt;/p&gt;
&lt;p&gt;We hope to never see a MUTATE to anything pending.&lt;/p&gt;
&lt;p&gt;I think the best way to think of this is that pending contains all variables that &lt;strong&gt;will be used&lt;/strong&gt; at some point below/later in the function, and therefore should be valid until then.&lt;/p&gt;
&lt;p&gt;To really understand it, let&#39;s see it in action.&lt;/p&gt;
&lt;p&gt;First, we &lt;strong&gt;look at the last line:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;  print_int(buff);        // USE buff (group g.buffs[])
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a USE, so we add it to the pending list. pending now has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;buff (group g.buffs[])&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, still going backwards, we encounter the line above it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;  e.add_buff();           // USE e (group g)
                          // MUTATE group g
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We see the MUTATE so we &lt;strong&gt;ensure no variables in pending are invalidated.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Specifically, we&#39;ll ensure that nothing in pending is pointing at anything under e.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;buff (group g.buffs[]) ... &lt;strong&gt;This matches!&lt;/strong&gt; Show a compile error.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&#39;s what just happened: buff was pointing at g.buffs[], which starts with the g we just mutated with add_buff. That means that buff is &lt;strong&gt;invalidated above the line where it&#39;s used,&lt;/strong&gt; which is a use-after-free.&lt;/p&gt;
&lt;p&gt;So the compiler shows an error here. &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://www.youtube.com/watch?v=y13n1CeyqjY&amp;amp;t=132s&quot;&gt;Huzzah!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;8&lt;/p&gt;
&lt;p&gt;First person to break it gets a prize!&lt;/p&gt;
&lt;h3&gt;Another Example&lt;/h3&gt;
&lt;p&gt;Let&#39;s see a &lt;strong&gt;correct program,&lt;/strong&gt; so we can see the backwards walk encountering a declaration.&lt;/p&gt;
&lt;p&gt;Here&#39;s the same program, but with e.add_buff(); moved up, to be the first line in the function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;struct Entity { hp int; buffs []int; }
func add_buff&amp;lt;g&amp;#39;&amp;gt;(self &amp;amp;Entity in g) mut(g) { ... }

func foo&amp;lt;g&amp;#39;&amp;gt;(
  e &amp;amp;Entity in g          // DECLARE e (group g)
) mut(g) {
  e.add_buff();           // USE e (group g)
                          // MUTATE group g
  let buff = &amp;amp;e.buffs[0]; // DECLARE buff (group g.buffs[])
  print_int(buff);        // USE buff (group g.buffs[])
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Like before, we start at the end, and get to this line:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;  print_int(buff);        // USE buff (group g.buffs[])
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...and see that it&#39;s a USE so we add buff to the pending list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;buff (group g.buffs[])&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now we go one line upward, to this line:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;  let buff = &amp;amp;e.buffs[0]; // DECLARE buff (group g.buffs[])
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This DECLAREs buff, so we &lt;strong&gt;remove&lt;/strong&gt; it from pending.&lt;/p&gt;
&lt;p&gt;pending is now empty.&lt;/p&gt;
&lt;p&gt;(That means that &lt;strong&gt;there are no variables that are used below/later in the function.&lt;/strong&gt;)&lt;/p&gt;
&lt;p&gt;Now we go one line upward, to this line:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;  e.add_buff();           // USE e (group g)
                          // MUTATE group g
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We see the MUTATE, so we &lt;strong&gt;ensure no variables in pending are invalidated.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There are no variables in pending, so nothing interesting happens.&lt;/p&gt;
&lt;p&gt;Then we see it USE e, so we &lt;strong&gt;add&lt;/strong&gt; it to pending:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;e (group g)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that&#39;s the end of the function!&lt;/p&gt;
&lt;p&gt;We made it all the way to the end without seeing any MUTATEing any pending variables, which means &lt;strong&gt;the program is memory-safe.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Why backwards?&lt;/h2&gt;
&lt;p&gt;There are three reasons: convenience, loops, and speed.&lt;/p&gt;
&lt;p&gt;Generally, going backwards is convenient for figuring out &lt;strong&gt;when a thing is last used.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For example, look at this function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;func attack(a &amp;amp;Entity in g, d &amp;amp;Entity in g) mut(g) {
  let a_power = a.calculate_attack_power();
  let a_energy_cost = a.calculate_attack_cost(d);
  let d_armor = d.calculate_defense();
  let d_energy_cost = d.calculate_defend_cost(a);
  a.use_energy(a_energy_cost);
  d.use_energy(d_energy_cost);
  d.damage(a_power - d_armor);
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we want to do &lt;em&gt;bookkeeping X&lt;/em&gt; when a is declared and do &lt;em&gt;bookkeeping Y&lt;/em&gt; when a is no longer needed, &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/reverse-borrow-checking#note9&quot;&gt;9&lt;/a&gt; we have two options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do a &lt;strong&gt;forward&lt;/strong&gt; scan. We encounter a&#39;s declaration, and do X. Then we continue, recording uses of a as we go. Once we hit the end of the function, we &lt;strong&gt;fetch/navigate to&lt;/strong&gt; the last recorded location, and do Y.&lt;/li&gt;
&lt;li&gt;Do a &lt;strong&gt;backward&lt;/strong&gt; scan. We encounter the last use of a, and do Y. Then we continue, looking for a&#39;s declaration. When we find it, we do X.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notice how the forward scan involved that extra fetch/navigate, because we couldn&#39;t recognize the last use when we encountered it.&lt;/p&gt;
&lt;p&gt;The backward scan was simpler.&lt;/p&gt;
&lt;p&gt;If you want to see another backwards scan help with destructor insertion, check out my &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://www.youtube.com/watch?v=IpuvQUVB8Cg&quot;&gt;LLVM talk&lt;/a&gt; from 2024! As many compiler people will tell you, scanning in reverse is useful for a lot of things.&lt;/p&gt;
&lt;p&gt;Going backwards is also better for loops.&lt;/p&gt;
&lt;p&gt;Here are a couple examples that I&#39;ve been using to think about loops: &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/reverse-borrow-checking#note10&quot;&gt;10&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is a correct program, but it shows how tricky it is to know if that observe(e) is valid.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;exported func main() {
  let arr = ArrayList&amp;lt;int&amp;gt;(3);
  let e = &amp;amp;arr[0];
  
  while ... {
    observe(e); // Valid `e` use.
    add_element(&amp;amp;arr);
    set e = &amp;amp;arr[0];
  }
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That e actually can come from two different places:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The e = &amp;amp;arr[0]; before the loop.&lt;/li&gt;
&lt;li&gt;The set e = &amp;amp;arr[0]; at the end of the loop.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A forward scan encountering observe(e) would need to &lt;strong&gt;look ahead&lt;/strong&gt; to the set e to conclude it&#39;s valid.&lt;/p&gt;
&lt;p&gt;This is a similar example without the set e.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;exported func main() {
  let arr: ArrayList&amp;lt;int&amp;gt; = ...;
  let e = &amp;amp;arr[0];

  while ... {
    observe(e); // Invalid `e` use.
    add_element(&amp;amp;arr);

  }
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without the set e, the e in the loop is invalidated by a &lt;em&gt;previous iteration&lt;/em&gt; of the loop.&lt;/p&gt;
&lt;p&gt;If we did a forward scan, we&#39;d need to &lt;strong&gt;look ahead&lt;/strong&gt; to see that there&#39;s no set e reviving e.&lt;/p&gt;
&lt;p&gt;This is a tricky problem. One can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scan ahead looking for those sets (then jump back).&lt;/li&gt;
&lt;li&gt;Do repeated forward passes, gaining more information each time, until things settle (a &amp;quot;dataflow fixpoint&amp;quot;).&lt;/li&gt;
&lt;li&gt;Do a forward pass to collect the information, and defer checking until later.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last one was tempting. Alas, its data structures ended up looking very complex, and it had the same &amp;quot;fetch/navigate&amp;quot; problem that we saw in the func attack example above.&lt;/p&gt;
&lt;p&gt;It was simpler to just go straight to V2&#39;s reverse-walking approach.&lt;/p&gt;
&lt;p&gt;I&#39;m also fairly certain V2&#39;s approach is faster, because it only has to process each node once in the phase 3 forward pass, and once in the phase 4 backward pass. &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/reverse-borrow-checking#note11&quot;&gt;11&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I haven&#39;t benchmarked that, so take it with a huge grain of salt. &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/reverse-borrow-checking#note12&quot;&gt;12&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But of course, the reverse-walk approach doesn&#39;t get loops for free. We still need some adjustments.&lt;/p&gt;
&lt;p&gt;9&lt;/p&gt;
&lt;p&gt;This bookkeeping might be decrementing a reference count, or &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://www.youtube.com/watch?v=IpuvQUVB8Cg&quot;&gt;adding a destructor call&lt;/a&gt;, or checking for use-after-frees, etc.&lt;/p&gt;
&lt;p&gt;10&lt;/p&gt;
&lt;p&gt;Note, in these examples, I use the name ArrayList, but in the real Valen compiler those are called Array, for weird historical reasons. That&#39;ll change soon.&lt;/p&gt;
&lt;p&gt;11&lt;/p&gt;
&lt;p&gt;Note, this doesn&#39;t mean that the algorithm is O(n) yet. The MUTATE still needs to check everything in the pending list. However, I think there&#39;s a way to speed that check up a lot. Fingers crossed!&lt;/p&gt;
&lt;p&gt;12&lt;/p&gt;
&lt;p&gt;V1 never had full loop support, so there&#39;s really nothing to benchmark against.&lt;/p&gt;
&lt;h2&gt;Reverse-Walking with Loops &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/reverse-borrow-checking#note13&quot;&gt;13&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The algorithm needs a little bit more to handle loops.&lt;/p&gt;
&lt;p&gt;Specifically, we&#39;ll do MUTATE and DECLARE differently, and we also react to LOOP START.&lt;/p&gt;
&lt;p&gt;We scan upward, looking for these events:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;When we USE a variable, &lt;strong&gt;add&lt;/strong&gt; it to the pending list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When we MUTATE anything:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ensure no variables in pending are invalidated.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add the mutation to the containing loop&#39;s mutations_after_this list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When we DECLARE a variable:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;remove&lt;/strong&gt; it from the pending list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If it wasn&#39;t invalidated by anything in mutations_after_this, add it to the containing loop&#39;s revived_after_this list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When we reach a LOOP START:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For each thing in pending, if it&#39;s invalidated by something in the loop&#39;s mutations_after_this, ensure it&#39;s also in the loop&#39;s revived_after_this. &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/reverse-borrow-checking#note14&quot;&gt;14&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&#39;s see what this does to this example. It&#39;s a &lt;strong&gt;correct&lt;/strong&gt; program, so there should be no compile error.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;exported func main() {
  let arr: ArrayList&amp;lt;int&amp;gt; = ...; // DECLARE arr (group arr)
  let e = &amp;amp;arr[0];               // DECLARE e (group arr[])
  
  while ... {                    // LOOP START
    observe(e);                  // USE e (group arr[])
    add_element(&amp;amp;arr);           // MUTATE arr (group arr)
    set e = &amp;amp;arr[0];             // DECLARE e (group arr[])
  }
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&#39;re walking backwards, so we start at the last line:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;    set e = &amp;amp;arr[0];             // DECLARE e (group arr[])
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s a DECLARE &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/reverse-borrow-checking#note15&quot;&gt;15&lt;/a&gt; so we do two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;remove&lt;/strong&gt; it from the pending list. It&#39;s not in it, so nothing happens.&lt;/li&gt;
&lt;li&gt;If it wasn&#39;t invalidated by anything in the containing mutations_after_this (it wasn&#39;t, because it&#39;s empty) add it to revived_after_this.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;revived_after_this now contains one entry: e.&lt;/p&gt;
&lt;p&gt;Now we walk up one line, seeing this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;    add_element(&amp;amp;arr);           // MUTATE arr (group arr)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s a MUTATE, so we do two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensure no variables in pending are invalidated. pending is empty, so nothing happens.&lt;/li&gt;
&lt;li&gt;Add the mutation to the containing loop&#39;s mutations_after_this list.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;mutations_after_this now contains one entry: arr.&lt;/p&gt;
&lt;p&gt;Now we walk up one line, seeing this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;    observe(e);                  // USE e (group arr[])
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s a USE, so we &lt;strong&gt;add&lt;/strong&gt; it to the pending list.&lt;/p&gt;
&lt;p&gt;pending now contains one entry: e (group arr[]).&lt;/p&gt;
&lt;p&gt;Now we walk up one line, seeing the loop start:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-valen&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Valen&quot;&gt;  while ... {                    // LOOP START
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So we do the LOOP START check: For each thing in pending, if it&#39;s invalidated by something in the loop&#39;s mutations_after_this, ensure it&#39;s in the loop&#39;s revived_after_this.&lt;/p&gt;
&lt;p&gt;In this case, pending has e (group arr[]). e &lt;em&gt;is&lt;/em&gt; invalidated by something in mutations_after_this. So check it&#39;s in the loop&#39;s revived_after_this (it is). Check passed, we&#39;re good.&lt;/p&gt;
&lt;p&gt;I&#39;ll skip the explanation for the top two DECLAREs, since we covered that before.&lt;/p&gt;
&lt;p&gt;And then we reach the start of the function! We encountered no errors, so the borrow checker can conclude &lt;strong&gt;this function is memory-safe.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And that&#39;s it! That&#39;s how we handle loops with this new reverse borrow checker.&lt;/p&gt;
&lt;p&gt;13&lt;/p&gt;
&lt;p&gt;Easter egg note!&lt;/p&gt;
&lt;p&gt;Sergeant Stubby was the star of the 102nd Infantry Regiment in World War I and travelled with his division to France to fight alongside the French. He served for 18 months and participated in 17 battles and four offensives on the Western Front.&lt;/p&gt;
&lt;p&gt;He received many awards, including a gold medal, a wound stripe, and two purple hearts.&lt;/p&gt;
&lt;p&gt;Sergeant Stubby has been called the most decorated war dog of the Great War and the only dog to be nominated and promoted to sergeant through combat.&lt;/p&gt;
&lt;p&gt;(&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://en.wikipedia.org/wiki/Sergeant_Stubby&quot;&gt;Source: Wikipedia&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;If you see this note, sneak the word &amp;quot;gold&amp;quot; into a &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://www.reddit.com/r/programming/comments/1x92rhh/a_new_way_to_think_about_borrow_checking_in/&quot;&gt;comment&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;(Congrats to &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://www.reddit.com/r/Valen/comments/1x92s1o/comment/phi1ieo/&quot;&gt;timpi4ever&lt;/a&gt; for finding this first!)&lt;/p&gt;
&lt;p&gt;14&lt;/p&gt;
&lt;p&gt;We don&#39;t remove anything from pending here, because those pending uses still need to be satisfied by the code above the loop.&lt;/p&gt;
&lt;p&gt;15&lt;/p&gt;
&lt;p&gt;Yes, I regret calling it DECLARE now, since really this is just re-pointing an existing variable.&lt;/p&gt;
&lt;h2&gt;More towards Rust&#39;s borrow checker?&lt;/h2&gt;
&lt;p&gt;There&#39;s one more big thing I want to change, eventually.&lt;/p&gt;
&lt;p&gt;Rust has this very nice ability to use facts from &lt;em&gt;anywhere&lt;/em&gt; in the function to figure out the lifetime of reference.&lt;/p&gt;
&lt;p&gt;For example, &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://play.rust-lang.org/?version=stable&amp;amp;mode=debug&amp;amp;edition=2024&amp;amp;gist=70b5f84ea984e1a3a60dff9e0110bcf9&quot;&gt;this Rust program&lt;/a&gt; looks at the later r = &amp;amp;b[0]; to figure out that r points at a &lt;em&gt;or&lt;/em&gt; b.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Rust&quot;&gt;&lt;span class=&quot;syntax-source syntax-rust&quot;&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-rust&quot;&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-rust&quot;&gt;&lt;span class=&quot;syntax-storage syntax-type syntax-function syntax-rust&quot;&gt;fn&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;syntax-entity syntax-name syntax-function syntax-rust&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-rust&quot;&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-parameters syntax-rust&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-rust&quot;&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-parameters syntax-rust&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parameters syntax-end syntax-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-rust&quot;&gt; &lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-rust&quot;&gt;&lt;span class=&quot;syntax-meta syntax-block syntax-rust&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-begin syntax-rust&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;syntax-storage syntax-type syntax-rust&quot;&gt;let&lt;/span&gt; a &lt;span class=&quot;syntax-keyword syntax-operator syntax-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;syntax-support syntax-macro syntax-rust&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-rust&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-rust&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-separator syntax-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-rust&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-separator syntax-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-rust&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-group syntax-end syntax-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-rust&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;syntax-storage syntax-type syntax-rust&quot;&gt;let&lt;/span&gt; b &lt;span class=&quot;syntax-keyword syntax-operator syntax-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;syntax-support syntax-macro syntax-rust&quot;&gt;vec!&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-rust&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-rust&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-separator syntax-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-rust&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-separator syntax-rust&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-rust&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-group syntax-end syntax-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-rust&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;syntax-storage syntax-type syntax-rust&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;syntax-storage syntax-modifier syntax-rust&quot;&gt;mut&lt;/span&gt; r &lt;span class=&quot;syntax-keyword syntax-operator syntax-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-rust&quot;&gt;&amp;amp;&lt;/span&gt;a&lt;span class=&quot;syntax-meta syntax-group syntax-rust&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-group syntax-end syntax-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-rust&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;syntax-keyword syntax-control syntax-rust&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;syntax-support syntax-function syntax-rust&quot;&gt;some_condition&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-rust&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-rust&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-group syntax-end syntax-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-block syntax-rust&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-begin syntax-rust&quot;&gt;{&lt;/span&gt;
    r &lt;span class=&quot;syntax-keyword syntax-operator syntax-rust&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-rust&quot;&gt;&amp;amp;&lt;/span&gt;b&lt;span class=&quot;syntax-meta syntax-group syntax-rust&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-rust&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-group syntax-end syntax-rust&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-rust&quot;&gt;;&lt;/span&gt;
  &lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-block syntax-rust&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-end syntax-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;syntax-support syntax-macro syntax-rust&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-rust&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-rust&quot;&gt;&lt;span class=&quot;syntax-string syntax-quoted syntax-double syntax-rust&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-string syntax-begin syntax-rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;syntax-constant syntax-other syntax-placeholder syntax-rust&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-string syntax-end syntax-rust&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-rust&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-separator syntax-rust&quot;&gt;,&lt;/span&gt; r&lt;span class=&quot;syntax-punctuation syntax-section syntax-group syntax-end syntax-rust&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-terminator syntax-rust&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-block syntax-rust&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-block syntax-end syntax-rust&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Valen doesn&#39;t do this yet; Valen&#39;s phase 3 (static grouping) is still doing normal one-directional inference.&lt;/p&gt;
&lt;p&gt;But if we change phase 3 into a full solve like rustc does, we can get some similar superpowers.&lt;/p&gt;
&lt;p&gt;The neat part: this wouldn&#39;t need to change phase 4&#39;s backward pass. In the end, we&#39;d have a solver for phase 3, and a backward pass for phase 4.&lt;/p&gt;
&lt;p&gt;It&#39;s hard to explain how cool that is to me. It&#39;s moments like these I suspect that I might be a compiler nerd. &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://www.youtube.com/watch?v=y13n1CeyqjY&amp;amp;t=132s&quot;&gt;Huzzah!&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;That&#39;s all for now&lt;/h2&gt;
&lt;p&gt;Valen&#39;s borrow checker is still pretty young, a mere 3,600 lines.&lt;/p&gt;
&lt;p&gt;And it&#39;s far from complete! We still have to add a lot of things to it, like interrupting control flow (break, continue), &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/reverse-borrow-checking#note16&quot;&gt;16&lt;/a&gt; associated groups, closures, &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/reverse-borrow-checking#note17&quot;&gt;17&lt;/a&gt; all the fun stuff.&lt;/p&gt;
&lt;p&gt;We&#39;ll get there one day. That day will be glorious.&lt;/p&gt;
&lt;p&gt;Thanks for reading!&lt;/p&gt;
&lt;p&gt;In the next few articles, I&#39;m hoping to explain more about how we&#39;ll blend in reference counting and generational references. I&#39;m also going to write about all the other languages exploring new memory safety approaches like this (&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://antelang.org/&quot;&gt;Ante&lt;/a&gt;, &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://github.com/carbon-language/carbon-lang&quot;&gt;Carbon&lt;/a&gt;, &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://github.com/zeta-lang/zeta&quot;&gt;Zeta&lt;/a&gt;, &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://github.com/devast8a/Fang&quot;&gt;Fang&lt;/a&gt;, &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://dilated.me/blog/posts/introduction-to-exclusion-typing/&quot;&gt;exclusion typing&lt;/a&gt;, and more!).&lt;/p&gt;
&lt;p&gt;This is just the tip of the iceberg, so stay tuned by subscribing to my &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/rss.xml&quot;&gt;RSS feed&lt;/a&gt;, &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://www.reddit.com/r/Valen/&quot;&gt;r/valen&lt;/a&gt;, or joining the &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://discord.gg/SNB8yGH&quot;&gt;Valen discord&lt;/a&gt;. And follow me on &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://bsky.app/profile/verdagon.bsky.social&quot;&gt;Bluesky&lt;/a&gt; and &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://fosstodon.org/@verdagon&quot;&gt;Mastodon&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Cheers,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Evan Ovadia&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;16&lt;/p&gt;
&lt;p&gt;The current plan is to first refactor things so the borrow checker is looking at a &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://en.wikipedia.org/wiki/Control-flow_graph&quot;&gt;control-flow graph&lt;/a&gt; instead of a typed AST. That should make interrupting control flow much easier.&lt;/p&gt;
&lt;p&gt;17&lt;/p&gt;
&lt;p&gt;I&#39;m pretty excited about closures. I think I found a &lt;em&gt;very&lt;/em&gt; elegant way to make them work. Stay tuned!&lt;/p&gt;
&lt;section class=&quot;footnotes&quot; data-footnotes&gt;
&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;Or &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://www.youtube.com/watch?v=IpuvQUVB8Cg&quot;&gt;destructor insertion&lt;/a&gt;, and now, checking memory safety! &lt;a href=&quot;#fnref-1&quot; class=&quot;footnote-backref&quot; data-footnote-backref data-footnote-backref-idx=&quot;1&quot; aria-label=&quot;Back to reference 1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;0% of this article was written by AI. &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://verdagon.dev/blog/personal-ai-policy&quot;&gt;More thoughts here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My stance: if you want someone to take the time to read something, take the time to write it by hand.&lt;/p&gt;
&lt;p&gt;Thanks for reading =) &lt;a href=&quot;#fnref-2&quot; class=&quot;footnote-backref&quot; data-footnote-backref data-footnote-backref-idx=&quot;2&quot; aria-label=&quot;Back to reference 2&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
</feed>
