<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://jackhuey.me/feed.xml" rel="self" type="application/atom+xml" /><link href="https://jackhuey.me/" rel="alternate" type="text/html" /><updated>2026-06-26T20:03:20+00:00</updated><id>https://jackhuey.me/feed.xml</id><title type="html">Jack Huey’s blog</title><subtitle>Just a simple blog, probably mostly about Rust.</subtitle><entry><title type="html">Fixing an unsoundness with the Polonius borrow checker</title><link href="https://jackhuey.me/rust/2026/06/26/polonius-unsoundness-fix.html" rel="alternate" type="text/html" title="Fixing an unsoundness with the Polonius borrow checker" /><published>2026-06-26T13:00:00+00:00</published><updated>2026-06-26T13:00:00+00:00</updated><id>https://jackhuey.me/rust/2026/06/26/polonius-unsoundness-fix</id><content type="html" xml:base="https://jackhuey.me/rust/2026/06/26/polonius-unsoundness-fix.html"><![CDATA[<p>If you’ve used Rust enough, you might have run into one or two limitations in the borrow checker. Maybe you tried to write a function like this, and got an error:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">get_default</span><span class="o">&lt;</span><span class="n">K</span><span class="p">,</span> <span class="n">V</span><span class="o">&gt;</span><span class="p">(</span>
    <span class="n">map</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">HashMap</span><span class="o">&lt;</span><span class="n">K</span><span class="p">,</span><span class="n">V</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="n">key</span><span class="p">:</span> <span class="n">K</span><span class="p">,</span>
<span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">V</span> <span class="p">{</span>
    <span class="k">match</span> <span class="n">map</span><span class="nf">.get_mut</span><span class="p">(</span><span class="o">&amp;</span><span class="n">key</span><span class="p">)</span> <span class="p">{</span>
        <span class="nf">Some</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">value</span><span class="p">,</span>
        <span class="nb">None</span> <span class="k">=&gt;</span> <span class="p">{</span>
            <span class="n">map</span><span class="nf">.insert</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="nn">V</span><span class="p">::</span><span class="nf">default</span><span class="p">());</span>
            <span class="n">map</span><span class="nf">.get_mut</span><span class="p">(</span><span class="o">&amp;</span><span class="n">key</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">()</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>I won’t go into details about this particular example, but this is a well-known problem referred to as <a href="https://rust-lang.github.io/rfcs/2094-nll.html#problem-case-3-conditional-control-flow-across-functions">“problem case 3”</a>.</p>

<p>You may know that there are ongoing efforts (for many years now!) to fix the borrow checker to “just work” for this example and others. That work has been dubbed “Polonius” and talked about in great detail by Niko Matsakis and others. Niko has <a href="https://smallcultfollowing.com/babysteps/categories/nll/">a series of posts</a> talking about Polonius and its predecessor NLL, as well as a <a href="https://smallcultfollowing.com/babysteps/series/polonius-revisited/">couple more recent posts</a> on the most recent approach to implementing Polonius-style borrow checking.</p>

<p>We’re getting <a href="https://rust-lang.github.io/rust-project-goals/2026/polonius.html">very close to stabilizing</a> the new iteration of the borrow checker, which has been coined “Polonius Alpha” (thanks in large part to <a href="https://github.com/lqd">lqd</a>), and I want to talk today about one little hiccup that was discovered where Polonius Alpha is unsound when using <code class="language-plaintext highlighter-rouge">impl Trait</code> (and associated types, but we’ll get there). I want to walk through the initial problem that was found, how it is more comprehensive than originally thought, and then the solution.</p>

<p>I won’t go into <em>too many</em> details of how Polonius works under the hood; for that, you should go read Niko’s latest couple blog posts, since they’re very good. Instead, I’m going to try to give only the details that matter to explain the problem and the solution.</p>

<h2 id="liveness--opaque-types--polonius-oh-my">Liveness &amp; opaque types &amp; Polonius, oh my</h2>

<h3 id="what-is-liveness-anyways">What is liveness, anyways?</h3>

<p>The first thing to talk about is <em>liveness</em>. Put simply, a variable is <em>live</em> if it could be used again:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">foo</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">x</span> <span class="o">=</span> <span class="nn">String</span><span class="p">::</span><span class="nf">from</span><span class="p">(</span><span class="s">"test"</span><span class="p">);</span> <span class="c1">//</span>
    <span class="k">let</span> <span class="n">y</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">x</span><span class="p">;</span>              <span class="c1">// -- x is live</span>
    <span class="nf">call_a</span><span class="p">();</span>                    <span class="c1">//  |  -- y is live</span>
    <span class="nf">call_b</span><span class="p">();</span>                    <span class="c1">//  |   |</span>
    <span class="nf">drop</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>                     <span class="c1">//  |  --</span>
    <span class="nf">call_c</span><span class="p">();</span>                    <span class="c1">//  |</span>
<span class="p">}</span>                                <span class="c1">// -- (x is implicitly dropped)</span>
</code></pre></div></div>

<p>Of course, it’s a bit more complicated than that: we don’t just think about live <em>variables</em>, but live <em>regions</em> (which are sort of the internal representation of a “lifetime”). For the above example, while <code class="language-plaintext highlighter-rouge">y</code> is live, so is a mutable <em>borrow</em> of <code class="language-plaintext highlighter-rouge">x</code>. So, because <code class="language-plaintext highlighter-rouge">y</code> is live at <code class="language-plaintext highlighter-rouge">call_b()</code>, we could not, for example, use <code class="language-plaintext highlighter-rouge">x</code> because <code class="language-plaintext highlighter-rouge">y</code> is later used.</p>

<p>This (and more) is of course available on stable today with NLL: when program flow is linear, borrow checking is “easy”. However, with Polonius Alpha, liveness calculation is extended to take into account branches within a function, too. And further, liveness is <em>combined</em> with known lifetime-outlives relationships to reduce false-positive borrow-check errors. However, incorrect liveness information can result in Polonius disregarding needed outlives requirements, leading to missed borrow-check errors and unsound programs being accepted. To read into the specifics of how liveness is used, Niko shares much more detail in his blog posts.</p>

<p>So, how is liveness calculated anyways? Let’s start with two simple examples:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">x</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="nb">u8</span><span class="p">;</span>

<span class="k">let</span> <span class="n">z</span><span class="p">:</span> <span class="nn">MyStruct</span><span class="p">::</span><span class="o">&lt;</span><span class="nv">'b</span><span class="o">&gt;</span><span class="p">;</span>
</code></pre></div></div>

<p>The first, we saw this above: as long as <code class="language-plaintext highlighter-rouge">x</code> is live, so is <code class="language-plaintext highlighter-rouge">'a</code>. The second is also pretty easy: as long as <code class="language-plaintext highlighter-rouge">z</code> is live, <code class="language-plaintext highlighter-rouge">'b</code> is too.</p>

<h3 id="liveness-for-opaque-types">Liveness for opaque types</h3>

<p>What about opaque types? (You may know them as <code class="language-plaintext highlighter-rouge">impl Trait</code>.)</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">rpit_lt</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">&gt;</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="p">(),</span> <span class="n">y</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'b</span> <span class="k">mut</span> <span class="p">())</span> <span class="k">-&gt;</span> <span class="k">impl</span> <span class="nb">Sized</span> <span class="o">+</span> <span class="nv">'a</span> <span class="o">+</span> <span class="k">use</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">x</span>
<span class="p">}</span>
<span class="k">fn</span> <span class="n">rpit_static</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">&gt;</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="p">(),</span> <span class="n">y</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'b</span> <span class="k">mut</span> <span class="p">())</span> <span class="k">-&gt;</span> <span class="k">impl</span> <span class="nb">Sized</span> <span class="o">+</span> <span class="k">'static</span> <span class="o">+</span> <span class="k">use</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>

<blockquote>
  <p><strong><em>NOTE:</em></strong>  I’m using an explicit <a href="https://blog.rust-lang.org/2024/09/05/impl-trait-capture-rules/#impl-traits-can-include-a-use-bound-to-specify-precisely-which-generic-types-and-lifetimes-they-use"><code class="language-plaintext highlighter-rouge">use</code> bound</a> to demonstrate the lifetime captures of the RPIT (return position impl trait) but starting in edition 2024, these captures are implicit.</p>
</blockquote>

<p>The first signature basically says “the opaque type can capture any variable with either <code class="language-plaintext highlighter-rouge">'a</code> or <code class="language-plaintext highlighter-rouge">'b</code>, but it must outlive <code class="language-plaintext highlighter-rouge">'a</code>”. The second says “the opaque type can capture any variable with <code class="language-plaintext highlighter-rouge">'a</code> or <code class="language-plaintext highlighter-rouge">'b</code>, but it must outlive <code class="language-plaintext highlighter-rouge">'static</code>”. Also note that in neither example do we know if <code class="language-plaintext highlighter-rouge">'b</code> outlives <code class="language-plaintext highlighter-rouge">'a</code>.</p>

<p>Now, if this is confusing to you, then you’re in good company. How can an opaque type be “allowed to capture a set of lifetimes” but simultaneously be required to outlive only one? Why is this useful to be able to say <em>anyways</em>?</p>

<p>For the question of “why do we need <code class="language-plaintext highlighter-rouge">use</code> bounds”, I would direct you to read <a href="https://blog.rust-lang.org/2024/09/05/impl-trait-capture-rules/#impl-traits-can-include-a-use-bound-to-specify-precisely-which-generic-types-and-lifetimes-they-use">this blog post</a>. tl;dr we want you to be able to be precise in the lifetimes that can be captured in an <code class="language-plaintext highlighter-rouge">impl Trait</code>, particularly when the <em>default</em> is to capture everything.</p>

<p>For the first question, consider the following snippet:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">x</span> <span class="o">=</span> <span class="o">&amp;</span><span class="p">();</span>
<span class="k">let</span> <span class="n">y</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">();</span>
<span class="k">let</span> <span class="n">a</span> <span class="o">=</span> <span class="nf">rpit_lt</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">);</span>
<span class="k">let</span> <span class="n">b</span> <span class="o">=</span> <span class="nf">rpit_lt</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">);</span>
<span class="nf">drop</span><span class="p">(</span><span class="n">a</span><span class="p">);</span>
<span class="nf">drop</span><span class="p">(</span><span class="n">b</span><span class="p">);</span>
</code></pre></div></div>

<p>Now, think about this: by default, if we don’t have the <code class="language-plaintext highlighter-rouge">'a</code> outlives bound, then the compiler must assume that both the lifetimes of <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">y</code> end up in the opaque type. So, from a compiler perspective, it’s not much different than</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">);</span>
<span class="k">let</span> <span class="n">b</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">);</span>
<span class="nf">drop</span><span class="p">(</span><span class="n">a</span><span class="p">);</span>
<span class="nf">drop</span><span class="p">(</span><span class="n">b</span><span class="p">);</span>
</code></pre></div></div>

<p>Both <code class="language-plaintext highlighter-rouge">a</code> and <code class="language-plaintext highlighter-rouge">b</code> contain the same mutable reference and because you drop <code class="language-plaintext highlighter-rouge">a</code> while <code class="language-plaintext highlighter-rouge">b</code> is live, this results in a borrow-check error. The <code class="language-plaintext highlighter-rouge">'a</code> outlives bound makes the compiler treat it more like:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">a</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span><span class="p">,);</span>
<span class="k">let</span> <span class="n">b</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span><span class="p">,);</span>
<span class="nf">drop</span><span class="p">(</span><span class="n">a</span><span class="p">);</span>
<span class="nf">drop</span><span class="p">(</span><span class="n">b</span><span class="p">);</span>
</code></pre></div></div>

<p>Only a shared reference is in both <code class="language-plaintext highlighter-rouge">a</code> and <code class="language-plaintext highlighter-rouge">b</code>, so the drop order doesn’t matter and this compiles fine.</p>

<p>The <code class="language-plaintext highlighter-rouge">'static</code> bound says that the opaque type cannot capture <em>any</em> lifetimes, so the compiler treats it roughly like:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">a</span> <span class="o">=</span> <span class="p">();</span>
<span class="k">let</span> <span class="n">b</span> <span class="o">=</span> <span class="p">();</span>
<span class="nf">drop</span><span class="p">(</span><span class="n">a</span><span class="p">);</span>
<span class="nf">drop</span><span class="p">(</span><span class="n">b</span><span class="p">);</span>
</code></pre></div></div>

<blockquote>
  <p>Yes, you could achieve the same effect by changing the <code class="language-plaintext highlighter-rouge">use</code> bound to not name the lifetimes that can’t be captured, but remember that this captures list is often <em>implicit</em>.</p>
</blockquote>

<p>So, intuitively, let’s think about liveness and opaque types:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">a</span> <span class="o">=</span> <span class="nn">rpit_lt</span><span class="p">::</span><span class="o">&lt;</span><span class="nv">'x</span><span class="p">,</span> <span class="nv">'y</span><span class="o">&gt;</span><span class="p">(</span><span class="o">..</span><span class="p">);</span>
<span class="k">let</span> <span class="n">b</span> <span class="o">=</span> <span class="nn">rpit_static</span><span class="p">::</span><span class="o">&lt;</span><span class="nv">'x</span><span class="p">,</span> <span class="nv">'y</span><span class="o">&gt;</span><span class="p">(</span><span class="o">..</span><span class="p">);</span>
</code></pre></div></div>

<p>For <code class="language-plaintext highlighter-rouge">a</code>, because the opaque type outlives <code class="language-plaintext highlighter-rouge">'x</code>, then we <em>only</em> need to treat that as live. For <code class="language-plaintext highlighter-rouge">b</code>, because the opaque type outlives <em>neither</em> <code class="language-plaintext highlighter-rouge">'x</code> or <code class="language-plaintext highlighter-rouge">'y</code>, then we don’t need to treat either as live.</p>

<h3 id="problems">Problems</h3>

<p>That’s how it works on stable today (as of <a href="https://github.com/rust-lang/rust/pull/116733">#116733</a>). That’s simple enough, right? Well, consider this variant:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">rpit</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">&gt;</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="o">&amp;</span><span class="nv">'b</span> <span class="p">())</span> <span class="k">-&gt;</span> <span class="k">impl</span> <span class="nb">Sized</span> <span class="o">+</span> <span class="nv">'a</span> <span class="o">+</span> <span class="k">use</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">x</span>
<span class="p">}</span>
</code></pre></div></div>

<p>I want to point out that the opaque type captures both <code class="language-plaintext highlighter-rouge">'a</code> and <code class="language-plaintext highlighter-rouge">'b</code> because of the nested references. Because there is an implied <code class="language-plaintext highlighter-rouge">'b: 'a</code> outlives relationship, the outlives bound holds.</p>

<p>Let’s look at a minimal example of how you can use (a slight variant of) this function to create an unsoundness with Polonius Alpha today:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="n">Swap</span><span class="p">:</span> <span class="nb">Sized</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">swap</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="k">Self</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">Swap</span> <span class="k">for</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">T</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">swap</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="k">Self</span><span class="p">)</span> <span class="p">{</span>
        <span class="nn">std</span><span class="p">::</span><span class="nn">mem</span><span class="p">::</span><span class="nf">swap</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">other</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="n">hide_ref</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">,</span> <span class="n">T</span><span class="p">:</span> <span class="k">'static</span><span class="o">&gt;</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="o">&amp;</span><span class="nv">'b</span> <span class="n">T</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">impl</span> <span class="n">Swap</span> <span class="o">+</span> <span class="nv">'a</span> <span class="p">{</span>
    <span class="n">x</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">dangle_ref</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="p">[</span><span class="nb">i32</span><span class="p">;</span> <span class="mi">3</span><span class="p">]</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">res</span> <span class="o">=</span> <span class="o">&amp;</span><span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">];</span>
    <span class="k">let</span> <span class="n">x</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">];</span>
    <span class="nf">hide_ref</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="n">res</span><span class="p">)</span><span class="nf">.swap</span><span class="p">(</span><span class="nf">hide_ref</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="o">&amp;</span><span class="n">x</span><span class="p">));</span>
    <span class="n">res</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Let me point out the problem: in <code class="language-plaintext highlighter-rouge">dangle_ref</code>, we return a <code class="language-plaintext highlighter-rouge">'static</code> reference to a local value, which can then be read for a use-after-free.</p>

<p>On stable, <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2024&amp;gist=f89c61363b55034aafe53627b88233d7">this fails</a> as expected: we don’t treat <code class="language-plaintext highlighter-rouge">'b</code> as live, but it doesn’t matter because NLL doesn’t combine liveness with outlives relationships to perform borrow-checking (at least, not in a way that matters for this example). But <em>Polonius does</em>.</p>

<p>For the details on <em>why</em> Polonius needs liveness, I’d suggest that you dig into Niko’s blog posts. In short, Polonius requires that for an outlives bound to be meaningful, variables <em>must be live</em> when the outlives bounds are required.</p>

<p>So, the fix here is to treat <code class="language-plaintext highlighter-rouge">'b</code> as live too. I’ll talk about how we actually do that later in the post, and the rules that we use. But, in short: any lifetime must be considered live if it could be captured; and, we can identify that precise set by considering both the <em>item definition</em> and also <em>where clauses</em> in scope.</p>

<h2 id="thats-a-simple-example-surely-this-isnt-hard">That’s a simple example, surely this isn’t hard?</h2>

<p>Oh, if only it was that simple. It turns out we also have to handle: associated types, rustc’s odd opaque representation, RPITITs, and extra bounds from where clauses.</p>

<h3 id="associated-types">Associated types!</h3>

<p>So, <code class="language-plaintext highlighter-rouge">impl Trait</code> has this problem because they can have an outlives bound. Actually, associated types have a similar ability:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="n">MyTrait</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">:</span> <span class="nv">'a</span><span class="o">&gt;</span><span class="p">:</span> <span class="nv">'a</span>
    <span class="k">where</span>
        <span class="k">Self</span><span class="p">:</span> <span class="nv">'a</span><span class="p">;</span>
    <span class="k">fn</span> <span class="n">changes</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="nv">'a</span> <span class="k">self</span><span class="p">,</span> <span class="n">x</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'b</span> <span class="k">mut</span> <span class="nb">u8</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Surely you can see the parallel:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">t</span> <span class="o">=</span> <span class="nf">make_something_that_impls_mytrait</span><span class="p">();</span>
<span class="k">let</span> <span class="n">x</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">();</span>
<span class="k">let</span> <span class="n">a</span> <span class="o">=</span> <span class="n">t</span><span class="nf">.changes</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
<span class="k">let</span> <span class="n">b</span> <span class="o">=</span> <span class="n">t</span><span class="nf">.changes</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
<span class="nf">drop</span><span class="p">(</span><span class="n">a</span><span class="p">);</span>
<span class="nf">drop</span><span class="p">(</span><span class="n">b</span><span class="p">);</span>
</code></pre></div></div>

<p>We want this to compile, because of the <code class="language-plaintext highlighter-rouge">'a</code> outlives bound on <code class="language-plaintext highlighter-rouge">MyTrait::Assoc</code>. We know that the type cannot contain <code class="language-plaintext highlighter-rouge">x</code> (because it has <code class="language-plaintext highlighter-rouge">'b</code> which doesn’t outlive <code class="language-plaintext highlighter-rouge">'a</code>); so in the example, there are no overlapping mutable references.</p>

<h3 id="lifetime-capture-of-impl-trait-in-rustc-is-weird">Lifetime capture of <code class="language-plaintext highlighter-rouge">impl Trait</code> in rustc is <em>weird</em></h3>

<p>Another piece of complexity in this problem stems from how <code class="language-plaintext highlighter-rouge">impl Trait</code> is represented in rustc.</p>

<p>If you have:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">foo</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">,</span> <span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="o">&amp;</span><span class="nv">'b</span> <span class="n">T</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">impl</span> <span class="nb">Sized</span> <span class="o">+</span> <span class="nv">'a</span> <span class="o">+</span> <span class="k">use</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">;</span>
</code></pre></div></div>

<p>That really looks something like:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">opaque</span> <span class="n">foo_opaque</span><span class="o">&lt;</span><span class="nv">'a1</span><span class="o">&gt;</span><span class="p">:</span> <span class="nb">Sized</span> <span class="o">+</span> <span class="nv">'a1</span><span class="p">;</span>
<span class="k">fn</span> <span class="n">foo</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">,</span> <span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="o">&amp;</span><span class="nv">'b</span> <span class="n">T</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nn">foo</span><span class="p">::</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">,</span> <span class="n">T</span><span class="o">&gt;</span><span class="p">::</span><span class="n">foo_opaque</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">;</span>
</code></pre></div></div>

<p>There are two important considerations about the new “opaque” definition:
1) It gets the parent lifetimes copied to itself (but not type or const params).
2) All the information available to the parent (i.e. where clauses and the function signature) <em>don’t</em> get copied.</p>

<p>The latter is <em>particularly</em> important, because the inputs and output of a function can provide <em>implied bounds</em> because those types must be <em>well-formed</em>. For the above, <code class="language-plaintext highlighter-rouge">&amp;'a mut &amp;'b T</code> must have been constructed, so callers of <code class="language-plaintext highlighter-rouge">foo</code> must prove that <code class="language-plaintext highlighter-rouge">'b: 'a</code> (also that <code class="language-plaintext highlighter-rouge">T: 'b</code>) and <code class="language-plaintext highlighter-rouge">foo</code> can just <em>assume</em> that holds.</p>

<h3 id="rpitits-return-position-impl-trait-in-traits">RPITITs (return position impl trait in traits)</h3>

<p>So far when we’ve discussed RPITs, they’ve been present in freestanding functions. Turns out, RPITs in traits have a quirk: they are represented internally as (generic) associated types. Imagine you have a definition:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="n">MyTrait</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="n">foo</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="k">impl</span> <span class="n">OtherTrait</span> <span class="o">+</span> <span class="nv">'a</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>That is represented as:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="n">MyTrait</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">FooRet</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">:</span> <span class="n">OtherTrait</span> <span class="o">+</span> <span class="nv">'a</span><span class="p">;</span>
    <span class="k">fn</span> <span class="n">foo</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">FooRet</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now, since we already need to apply a fix for associated types (see above), that seems fine. Right? Of course it’s not that simple! But we’ll get there later.</p>

<h3 id="extra-information-from-where-clauses">Extra information from <code class="language-plaintext highlighter-rouge">where clauses</code></h3>

<p>Let’s start with another example:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">rpit</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="p">())</span> <span class="k">-&gt;</span> <span class="k">impl</span> <span class="nb">Sized</span> <span class="o">+</span> <span class="k">use</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This is an error today (and with Polonius on nightly, to be fair):</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">x</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">();</span>
<span class="k">let</span> <span class="n">a</span> <span class="o">=</span> <span class="nf">rpit</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
<span class="k">let</span> <span class="n">b</span> <span class="o">=</span> <span class="nf">rpit</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
<span class="nf">drop</span><span class="p">(</span><span class="n">a</span><span class="p">);</span>
<span class="nf">drop</span><span class="p">(</span><span class="n">b</span><span class="p">);</span>
</code></pre></div></div>

<p>This is an error for the same reasons we talked about before: the opaque type could contain the mutable reference. However, there is a nightly feature that allows you to name opaque types to use them in where clauses (return type notation, RTN). With that, you can add additional information about the opaque type:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">foo</span><span class="p">()</span> <span class="k">where</span> <span class="nf">rpit</span><span class="p">(</span><span class="o">..</span><span class="p">):</span> <span class="k">'static</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">x</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">();</span>
    <span class="k">let</span> <span class="n">a</span> <span class="o">=</span> <span class="nf">rpit</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
    <span class="k">let</span> <span class="n">b</span> <span class="o">=</span> <span class="nf">rpit</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
    <span class="nf">drop</span><span class="p">(</span><span class="n">a</span><span class="p">);</span>
    <span class="nf">drop</span><span class="p">(</span><span class="n">b</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<blockquote>
  <p><strong>Note:</strong> The RTN feature is <em>most useful</em> when used for <em>trait</em> methods, but the idea translates the same here.</p>
</blockquote>

<p>We ideally would let this compile as-if the <code class="language-plaintext highlighter-rouge">'static</code> outlives bound was on the <code class="language-plaintext highlighter-rouge">impl Trait</code> itself.</p>

<p>Of course, you don’t need RTN to add additional bounds for associated types, so this is something we need to consider even on stable today:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="n">MyTrait</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span>
    <span class="k">where</span>
        <span class="k">Self</span><span class="p">:</span> <span class="nv">'a</span><span class="p">;</span>
    <span class="k">fn</span> <span class="n">foo</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="n">bar</span><span class="o">&lt;</span><span class="n">T</span><span class="p">:</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">(</span><span class="k">mut</span> <span class="n">t</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span>
<span class="k">where</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">:</span> <span class="k">'static</span><span class="p">,</span>
<span class="p">{</span>
    <span class="k">let</span> <span class="n">a</span> <span class="o">=</span> <span class="n">t</span><span class="nf">.foo</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">b</span> <span class="o">=</span> <span class="n">t</span><span class="nf">.foo</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="though-this-be-madness-yet-there-is-method-int">Though this be madness, yet there is method in’t</h2>

<p>We’ve gone through what the source of the unsoundness is and the key considerations for what we need to keep in mind when fixing it. So, let’s talk about the solution.</p>

<p>Remember, given an opaque type, we want to know what lifetimes can be contained inside it and we need to consider those <em>live</em> for borrowck (and elsewhere).</p>

<p>Let’s go back to this example:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">rpit</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">&gt;</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="k">mut</span> <span class="o">&amp;</span><span class="nv">'b</span> <span class="p">())</span> <span class="k">-&gt;</span> <span class="k">impl</span> <span class="nb">Sized</span> <span class="o">+</span> <span class="nv">'a</span> <span class="o">+</span> <span class="k">use</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">x</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Starting with the <code class="language-plaintext highlighter-rouge">'a</code> outlives bound: this tells us that the opaque type can <em>only</em> contain lifetimes that we <em>know</em> outlive <code class="language-plaintext highlighter-rouge">'a</code>. Or, put differently, any params that outlive <code class="language-plaintext highlighter-rouge">'a</code> <em>can</em> be contained within the opaque type (with a caveat below). And so, we must mark these lifetimes as <em>live</em>. This is the root of the unsoundness: we don’t do that properly today.</p>

<blockquote>
  <p><strong>Note:</strong> It’s not entirely true that we have to know <em>all</em> the params that outlive <code class="language-plaintext highlighter-rouge">'a</code> to be sound; we only need to know all the params that the <em>function</em> knows to outlive <code class="language-plaintext highlighter-rouge">'a</code> (otherwise the function would not allow that to be contained in the opaque type).</p>
</blockquote>

<p>Now that caveat: <code class="language-plaintext highlighter-rouge">use&lt;'a, 'b&gt;</code> is the explicit precise capture list, but you can imagine that more often this is <em>implicitly</em> calculated. In either case, this gives us an <em>upper bound</em> on the params that we need to consider live; we don’t need to consider <em>all</em> params that outlive <code class="language-plaintext highlighter-rouge">'a</code>, only those that can be captured.</p>

<p>So, how do we identify params that can be captured and outlive <code class="language-plaintext highlighter-rouge">'a</code>?</p>

<p>This is where <code class="language-plaintext highlighter-rouge">&amp;'a mut &amp;'b ()</code> comes in. Or, really, the <em>entire</em> function signature and its where clauses. As mentioned previously, this function’s input argument tells us that <code class="language-plaintext highlighter-rouge">'b: 'a</code>. We combine these <em>implied</em> bounds from the function’s signature with the <em>explicit</em> where clauses. Fortunately, there is existing code within the compiler to get all the explicit and implied bounds for a given item (in this case, for a given function).</p>

<p>Of course, there is a major consideration here: the opaque type has that weird representation where lifetime params are duplicated and where clauses are not copied. The fix is relatively simple <em>in theory</em>: we map the opaque’s parameters back to the parent function, find the known outlives relationship <em>there</em>, and then map back.</p>

<p>So, to know what params to consider live on <code class="language-plaintext highlighter-rouge">rpit</code>, we do the following:</p>

<p>1) See that there is an outlives bound on <code class="language-plaintext highlighter-rouge">'a</code>.
2) Map that lifetime to the parent function.
3) For each param on the function (here <code class="language-plaintext highlighter-rouge">'a</code> and <code class="language-plaintext highlighter-rouge">'b</code>), use the where clauses and implied bounds to test if we know that it outlives <code class="language-plaintext highlighter-rouge">'a</code>. In this case, <em>both</em> do.
4) Map this larger set back to <em>captured</em> params on opaque (in this case, both <code class="language-plaintext highlighter-rouge">'a</code> and <code class="language-plaintext highlighter-rouge">'b</code> are captured).
5) Substitute the <em>actual</em> used values for the params.
6) Mark all lifetimes in these values as live.</p>

<p>Let’s go through a much more complicated example. I’m adding a bunch of complexity here not just to the example, but to the explanation too. This much more closely matches the actual representation and implementation, but also means there are concepts I haven’t otherwise covered. I’ll do my best to explain:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">rpit2</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">,</span> <span class="nv">'c</span><span class="p">,</span> <span class="nv">'d</span><span class="p">:</span> <span class="nv">'b</span><span class="p">,</span> <span class="n">U</span><span class="p">:</span> <span class="nv">'a</span><span class="o">&gt;</span><span class="p">(</span>
    <span class="n">x</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="o">&amp;</span><span class="nv">'b</span> <span class="nb">u8</span><span class="p">,</span>
    <span class="n">y</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'c</span> <span class="nb">u8</span><span class="p">,</span>
    <span class="n">z</span><span class="p">:</span> <span class="n">U</span><span class="p">,</span>
<span class="p">)</span> <span class="k">-&gt;</span> <span class="k">impl</span> <span class="nb">Sized</span> <span class="o">+</span> <span class="nv">'a</span> <span class="o">+</span> <span class="k">use</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">,</span> <span class="nv">'c</span><span class="p">,</span> <span class="n">U</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">z</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Which gets represented and used like:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">opaque</span> <span class="n">rpit2_opaque</span><span class="o">&lt;</span><span class="nv">'a1</span><span class="p">,</span> <span class="nv">'b1</span><span class="p">,</span> <span class="nv">'c1</span><span class="o">&gt;</span><span class="p">:</span> <span class="nb">Sized</span> <span class="o">+</span> <span class="nv">'a1</span><span class="p">;</span>
<span class="k">fn</span> <span class="n">rpit2_lowered</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">,</span> <span class="nv">'c</span><span class="p">,</span> <span class="nv">'d</span><span class="p">:</span> <span class="nv">'b</span><span class="p">,</span> <span class="n">U</span><span class="p">:</span> <span class="nv">'a</span><span class="o">&gt;</span><span class="p">(</span>
    <span class="n">x</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="o">&amp;</span><span class="nv">'b</span> <span class="nb">u8</span><span class="p">,</span>
    <span class="n">y</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'c</span> <span class="nb">u8</span><span class="p">,</span>
    <span class="n">z</span><span class="p">:</span> <span class="n">U</span><span class="p">,</span>
<span class="p">)</span> <span class="k">-&gt;</span> <span class="nn">rpit2</span><span class="p">::</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">,</span> <span class="nv">'c</span><span class="p">,</span> <span class="nv">'d</span><span class="p">,</span> <span class="n">U</span><span class="o">&gt;</span><span class="p">::</span><span class="n">rpit2_opaque</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">,</span> <span class="nv">'c</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">z</span><span class="p">)</span>
<span class="p">}</span>

<span class="k">let</span> <span class="n">s</span><span class="p">:</span> <span class="n">OtherStruct</span><span class="o">&lt;</span><span class="nv">'_</span><span class="o">&gt;</span> <span class="o">=</span> <span class="o">...</span><span class="p">;</span>
<span class="k">let</span> <span class="n">out</span> <span class="o">=</span> <span class="nf">rpit2</span><span class="p">(</span><span class="o">&amp;&amp;</span><span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="mi">0</span><span class="p">,</span> <span class="n">s</span><span class="p">);</span> <span class="c1">// out has a type of:</span>
<span class="c1">//    `rpit2::&lt;'?1, '?2, '?3, '?4, OtherStruct::&lt;'?5&gt;&gt;::rpit2_opaque&lt;'?6, '?7, '?8&gt;`</span>
<span class="c1">// `'?X` is a *lifetime variable* and `?Y` is a *type variable*</span>
</code></pre></div></div>

<p>1) We see that there is a <code class="language-plaintext highlighter-rouge">'a1</code> outlives bound on <code class="language-plaintext highlighter-rouge">rpit2_opaque</code>.
2) Map this back to <code class="language-plaintext highlighter-rouge">rpit2</code>: <code class="language-plaintext highlighter-rouge">'a1</code> matches <code class="language-plaintext highlighter-rouge">'a</code>.
3) Check outlives relationships:
    - <code class="language-plaintext highlighter-rouge">'a: 'a</code> trivially holds
    - <code class="language-plaintext highlighter-rouge">'b: 'a</code> holds because of <code class="language-plaintext highlighter-rouge">&amp;'a &amp;'b u8</code>
    - <code class="language-plaintext highlighter-rouge">'c: 'a</code> does not hold
    - <code class="language-plaintext highlighter-rouge">'d: 'a</code> holds because of the <code class="language-plaintext highlighter-rouge">'d: 'b</code> bound and <code class="language-plaintext highlighter-rouge">'b: 'a</code>
    - <code class="language-plaintext highlighter-rouge">U: 'a</code> holds because of the <code class="language-plaintext highlighter-rouge">U: 'a</code> bound
4) Map back to the captured opaque params:
    - <code class="language-plaintext highlighter-rouge">'a</code> =&gt; <code class="language-plaintext highlighter-rouge">'a1</code>
    - <code class="language-plaintext highlighter-rouge">'b</code> =&gt; <code class="language-plaintext highlighter-rouge">'b1</code>
    - <code class="language-plaintext highlighter-rouge">'d</code> =&gt; not captured
    - <code class="language-plaintext highlighter-rouge">U</code> =&gt; <code class="language-plaintext highlighter-rouge">U</code>
5) Substitute params with actual values:
    - <code class="language-plaintext highlighter-rouge">'a1</code> =&gt; <code class="language-plaintext highlighter-rouge">'?6</code>
    - <code class="language-plaintext highlighter-rouge">'b1</code> =&gt; <code class="language-plaintext highlighter-rouge">'?7</code>
    - <code class="language-plaintext highlighter-rouge">U</code> =&gt; <code class="language-plaintext highlighter-rouge">OtherStruct::&lt;'?5&gt;</code>
6) Mark lifetimes <code class="language-plaintext highlighter-rouge">'?6</code>, <code class="language-plaintext highlighter-rouge">'?7</code>, <code class="language-plaintext highlighter-rouge">'?5</code> as live</p>

<p>Before this change, we only would have marked <code class="language-plaintext highlighter-rouge">'?6</code> as live.</p>

<p>I also want to point out that the above can be generalized a bit: given <em>some</em> lifetime on the opaque, we can find the params that <em>must</em> be considered live (steps 2-4). This will be important later, but for now let’s assume <em>this</em> is the generalization we want and work to apply it to other places.</p>

<blockquote>
  <p><strong>Note:</strong> Although RPITITs are internally represented as associated types, the information to calculate all the outlives relationships (namely the where clauses and the well-formed function signature) is not available. Therefore, the algorithm for calculating live params for RPITITs is the same as for RPITs.</p>
</blockquote>

<h3 id="associated-types-1">Associated types</h3>

<p>Implementing this logic for associated types is easy.</p>

<blockquote>
  <p>Fortunately, there is existing code within the compiler to get all the explicit and implied bounds for a given item.</p>
</blockquote>

<p>This code <em>just works</em> for them.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="n">MyTrait</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">:</span> <span class="nv">'a</span><span class="p">,</span> <span class="n">T</span><span class="p">:</span> <span class="nv">'a</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We can ask “what params outlive <code class="language-plaintext highlighter-rouge">'a</code>” and get back <code class="language-plaintext highlighter-rouge">'a</code>, <code class="language-plaintext highlighter-rouge">'b</code>, and <code class="language-plaintext highlighter-rouge">T</code>. We don’t need to do any lifetime mapping tricks or filtering for captured params; those only matter for RPITs.</p>

<h3 id="outlives-bounds-in-where-clauses">Outlives bounds in where clauses</h3>

<blockquote>
  <p><strong>Warning:</strong> this section is as complicated (if not more) as finding live params on the opaque or associated type definition.</p>
</blockquote>

<p>Do you remember how you write today:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">bar</span><span class="o">&lt;</span><span class="n">T</span><span class="p">:</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">(</span><span class="k">mut</span> <span class="n">t</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span>
<span class="k">where</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">:</span> <span class="k">'static</span><span class="p">,</span>
<span class="p">{</span>
    <span class="o">...</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And expect that <code class="language-plaintext highlighter-rouge">T::Assoc&lt;'a&gt;</code> can’t <em>actually</em> contain anything that uses the lifetime param. However, here are <em>many</em> other examples to consider:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="n">MyTrait</span> <span class="p">{</span> <span class="k">type</span> <span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">:</span> <span class="nv">'a</span><span class="p">,</span> <span class="nv">'c</span><span class="o">&gt;</span><span class="p">;</span> <span class="p">}</span>

<span class="k">fn</span> <span class="n">fn1</span><span class="o">&lt;</span><span class="nv">'x</span><span class="p">,</span> <span class="nv">'y</span><span class="p">,</span> <span class="nv">'z</span><span class="p">,</span> <span class="n">T</span><span class="p">:</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">()</span> <span class="k">where</span>
    <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'x</span><span class="p">,</span> <span class="nv">'y</span><span class="p">,</span> <span class="nv">'z</span><span class="o">&gt;</span><span class="p">:</span> <span class="k">'static</span><span class="p">,</span>

<span class="k">fn</span> <span class="n">fn2</span><span class="o">&lt;</span><span class="nv">'x</span><span class="p">,</span> <span class="nv">'y</span><span class="p">,</span> <span class="nv">'z</span><span class="p">,</span> <span class="n">T</span><span class="p">:</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">()</span> <span class="k">where</span>
    <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'x</span><span class="p">,</span> <span class="nv">'y</span><span class="p">,</span> <span class="nv">'z</span><span class="o">&gt;</span><span class="p">:</span> <span class="nv">'x</span><span class="p">,</span>

<span class="k">fn</span> <span class="n">fn3</span><span class="o">&lt;</span><span class="nv">'x</span><span class="p">,</span> <span class="nv">'y</span><span class="p">,</span> <span class="nv">'z</span><span class="p">,</span> <span class="n">T</span><span class="p">:</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">()</span> <span class="k">where</span>
    <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'x</span><span class="p">,</span> <span class="nv">'y</span><span class="p">,</span> <span class="nv">'z</span><span class="o">&gt;</span><span class="p">:</span> <span class="nv">'z</span><span class="p">,</span>

<span class="k">fn</span> <span class="n">fn4</span><span class="o">&lt;</span><span class="nv">'x</span><span class="p">,</span> <span class="n">T</span><span class="p">:</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">()</span> <span class="k">where</span>
    <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'x</span><span class="p">,</span> <span class="nv">'x</span><span class="p">,</span> <span class="nv">'x</span><span class="o">&gt;</span><span class="p">:</span> <span class="nv">'x</span><span class="p">,</span>

<span class="k">fn</span> <span class="n">fn5</span><span class="o">&lt;</span><span class="nv">'x</span><span class="p">,</span> <span class="nv">'y</span><span class="p">,</span> <span class="n">T</span><span class="p">:</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">()</span> <span class="k">where</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'h</span><span class="o">&gt;</span> <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'x</span><span class="p">,</span> <span class="nv">'y</span><span class="p">,</span> <span class="nv">'h</span><span class="o">&gt;</span><span class="p">:</span> <span class="nv">'h</span><span class="p">,</span>

<span class="k">fn</span> <span class="n">fn6</span><span class="o">&lt;</span><span class="nv">'x</span><span class="p">,</span> <span class="n">T</span><span class="p">:</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">()</span> <span class="k">where</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'h</span><span class="o">&gt;</span> <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'x</span><span class="p">,</span> <span class="nv">'x</span><span class="o">&gt;</span><span class="p">:</span> <span class="nv">'x</span><span class="p">,</span>

<span class="k">fn</span> <span class="n">fn7</span><span class="o">&lt;</span><span class="nv">'x</span><span class="p">,</span> <span class="n">T</span><span class="p">:</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">()</span> <span class="k">where</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'h</span><span class="o">&gt;</span> <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'h</span><span class="p">,</span> <span class="nv">'h</span><span class="o">&gt;</span><span class="p">:</span> <span class="nv">'x</span><span class="p">,</span>

<span class="k">fn</span> <span class="n">fn8</span><span class="o">&lt;</span><span class="n">T</span><span class="p">:</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">()</span> <span class="k">where</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'i</span><span class="p">,</span> <span class="nv">'j</span><span class="o">&gt;</span> <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'i</span><span class="p">,</span> <span class="nv">'j</span><span class="o">&gt;</span><span class="p">:</span> <span class="nv">'h</span><span class="p">,</span>

<span class="k">fn</span> <span class="n">fn9</span><span class="o">&lt;</span><span class="n">T</span><span class="p">:</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">()</span> <span class="k">where</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'i</span><span class="p">,</span> <span class="nv">'j</span><span class="o">&gt;</span> <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'i</span><span class="p">,</span> <span class="nv">'j</span><span class="o">&gt;</span><span class="p">:</span> <span class="nv">'h</span><span class="p">,</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'i</span><span class="p">,</span> <span class="nv">'j</span><span class="o">&gt;</span> <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'i</span><span class="p">,</span> <span class="nv">'j</span><span class="o">&gt;</span><span class="p">:</span> <span class="nv">'j</span><span class="p">,</span>

<span class="k">fn</span> <span class="n">fn10</span><span class="o">&lt;</span><span class="n">T</span><span class="p">:</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">()</span> <span class="k">where</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'h</span><span class="o">&gt;</span> <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'h</span><span class="p">,</span> <span class="nv">'h</span><span class="o">&gt;</span><span class="p">:</span> <span class="nv">'h</span><span class="p">,</span>

<span class="k">fn</span> <span class="n">fn11</span><span class="o">&lt;</span><span class="n">T</span><span class="p">:</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">()</span> <span class="k">where</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'h</span><span class="o">&gt;</span> <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'h</span><span class="p">,</span> <span class="nv">'h</span><span class="o">&gt;</span><span class="p">:</span> <span class="k">'static</span><span class="p">,</span>

<span class="k">fn</span> <span class="n">fn12</span><span class="o">&lt;</span><span class="n">T</span><span class="p">:</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">()</span> <span class="k">where</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'i</span><span class="p">,</span> <span class="nv">'j</span><span class="o">&gt;</span> <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'i</span><span class="p">,</span> <span class="nv">'j</span><span class="o">&gt;</span><span class="p">:</span> <span class="k">'static</span><span class="p">,</span>
</code></pre></div></div>

<p>That’s a lot! But generally, there are a couple different questions to consider here:</p>
<ul>
  <li>Are the lifetimes in the associated type from the <em>function</em> or from a <code class="language-plaintext highlighter-rouge">for&lt;...&gt;</code>?</li>
  <li>Is the outlived lifetime from the <em>function</em> or from a <code class="language-plaintext highlighter-rouge">for&lt;...&gt;</code> (or <code class="language-plaintext highlighter-rouge">'static</code>)?</li>
  <li>What happens with multiple where clauses?</li>
  <li>When the same lifetime is repeated in the associated type, what does that mean?</li>
</ul>

<p>So, let’s work through these, and see if we can develop an intuition about the general rule here. We’ll start with actually backing up a bit, and thinking about what the implementation of the associated type could look like. All of these are “valid”:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span> <span class="n">MyTrait</span> <span class="k">for</span> <span class="n">Foo</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">,</span> <span class="nv">'c</span><span class="o">&gt;</span> <span class="o">=</span> <span class="p">();</span> <span class="c1">// No lifetimes used</span>
    <span class="k">type</span> <span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">,</span> <span class="nv">'c</span><span class="o">&gt;</span> <span class="o">=</span> <span class="p">(</span><span class="o">&amp;</span><span class="nv">'a</span> <span class="o">&amp;</span><span class="nv">'b</span> <span class="p">(),</span> <span class="o">&amp;</span><span class="nv">'c</span> <span class="p">());</span> <span class="c1">// All used</span>
    <span class="k">type</span> <span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">,</span> <span class="nv">'c</span><span class="o">&gt;</span> <span class="o">=</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="o">&amp;</span><span class="nv">'b</span> <span class="p">();</span> <span class="c1">// Only some</span>
    <span class="k">type</span> <span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">,</span> <span class="nv">'c</span><span class="o">&gt;</span> <span class="o">=</span> <span class="o">&amp;</span><span class="nv">'c</span> <span class="p">();</span> <span class="c1">// Only one</span>
<span class="p">}</span>
</code></pre></div></div>

<p>If you have a bound like <code class="language-plaintext highlighter-rouge">for&lt;'h, 'i, 'j&gt; T::Assoc&lt;'h, 'i, 'j&gt;: 'h</code>, that rules out the second and fourth definitions, because <code class="language-plaintext highlighter-rouge">'c: 'a</code> doesn’t hold. It does not rule out the third, because we know that <code class="language-plaintext highlighter-rouge">'b: 'a</code> holds because of the trait definition.</p>

<p>Now, what about something like <code class="language-plaintext highlighter-rouge">fn2</code> above with the bound <code class="language-plaintext highlighter-rouge">T::Assoc&lt;'x, 'y, 'z&gt;: 'x</code>? Well, <em>free</em> lifetimes (i.e. defined on the function, not <em>within</em> the function) are <em>always</em> live. So, when all the lifetimes contained are <em>free</em>, then they are all <em>live</em>. What about a bound like <code class="language-plaintext highlighter-rouge">for&lt;'h&gt; T::Assoc&lt;'x, 'h, 'x&gt;: 'x</code>? Let’s think about what that could mean if the impl definition looks like the third above:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">foo</span><span class="o">&lt;</span><span class="nv">'x</span><span class="o">&gt;</span><span class="p">()</span>
<span class="k">where</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'h</span><span class="o">&gt;</span> <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'x</span><span class="p">,</span> <span class="nv">'h</span><span class="p">,</span> <span class="nv">'x</span><span class="o">&gt;</span><span class="p">:</span> <span class="nv">'x</span><span class="p">,</span>
<span class="p">{</span>
    <span class="k">let</span> <span class="n">val</span><span class="p">:</span> <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'x</span><span class="p">,</span> <span class="nv">'_</span><span class="p">,</span> <span class="nv">'x</span><span class="o">&gt;</span> <span class="o">=</span> <span class="o">&amp;&amp;</span><span class="p">();</span> <span class="c1">// &amp;'?1 &amp;'?2 ();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Here, <code class="language-plaintext highlighter-rouge">'?2</code> must outlive <code class="language-plaintext highlighter-rouge">'?1</code> because of the well-formedness of the right side. <em>However</em>, <code class="language-plaintext highlighter-rouge">'?1</code> must <em>equal</em> <code class="language-plaintext highlighter-rouge">'x</code> because of the impl. Therefore, <code class="language-plaintext highlighter-rouge">'?2</code> must outlive <code class="language-plaintext highlighter-rouge">'x</code> and <em>also</em> be live.</p>

<p>What about this example, with the fourth impl definition:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">bar</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">&gt;</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="p">(),</span> <span class="n">b</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'b</span> <span class="p">())</span> <span class="k">-&gt;</span> <span class="o">&lt;</span><span class="n">Foo</span> <span class="k">as</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="n">b</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="n">foo</span><span class="o">&lt;</span><span class="nv">'x</span><span class="o">&gt;</span><span class="p">()</span>
<span class="k">where</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'i</span><span class="o">&gt;</span> <span class="o">&lt;</span><span class="n">Foo</span> <span class="k">as</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'i</span><span class="p">,</span> <span class="nv">'x</span><span class="o">&gt;</span><span class="p">:</span> <span class="nv">'x</span><span class="p">,</span>
<span class="p">{</span>
    <span class="k">let</span> <span class="n">a</span> <span class="o">=</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="o">&amp;</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">b</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'x</span> <span class="p">()</span> <span class="o">=</span> <span class="o">&amp;</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">val2</span> <span class="o">=</span> <span class="nf">bar</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span>
    <span class="k">let</span> <span class="n">val3</span> <span class="o">=</span> <span class="nf">bar</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span>
    <span class="nf">drop</span><span class="p">(</span><span class="n">val2</span><span class="p">);</span>
    <span class="nf">drop</span><span class="p">(</span><span class="n">val3</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>In this case, because of the outlives bound we know that neither <code class="language-plaintext highlighter-rouge">'h</code> and <code class="language-plaintext highlighter-rouge">'i</code> can be in the associated type. So, we should be safe to only treat <code class="language-plaintext highlighter-rouge">'x</code> as live (which it already <em>must</em> be because it is <em>free</em>). <em>However</em>, we don’t do that <em>today</em> (on stable); we treat everything as live. So, that isn’t changed: when the outlives bound is a <em>free variable</em>, we don’t restrict the things that <em>could</em> be live.</p>

<p>So, next example. We’ll look at <code class="language-plaintext highlighter-rouge">fn10</code> from above:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">fn10</span><span class="o">&lt;</span><span class="n">T</span><span class="p">:</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">()</span> <span class="k">where</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'h</span><span class="o">&gt;</span> <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'h</span><span class="p">,</span> <span class="nv">'h</span><span class="o">&gt;</span><span class="p">:</span> <span class="nv">'h</span><span class="p">,</span>
</code></pre></div></div>

<p>This means that <em>all</em> three lifetimes may appear in the associated type, and therefore must be considered live.</p>

<p>Of course, if we have <code class="language-plaintext highlighter-rouge">for&lt;'h, 'i, 'j&gt; T::Assoc&lt;'h, 'i, 'j&gt;: 'h</code>, then <code class="language-plaintext highlighter-rouge">'h</code> is obviously allowed to be contained in the associated type; but so is <code class="language-plaintext highlighter-rouge">'i</code>, because we know from the trait that the second lifetime outlives the first.</p>

<blockquote>
  <p><strong>Note:</strong> This doesn’t <em>quite</em> work today, because you will get an error that we don’t know that <code class="language-plaintext highlighter-rouge">'i: 'h</code>. But, we eventually want to make this work.</p>
</blockquote>

<p>So, let’s work through a general algorithm here, for the <code class="language-plaintext highlighter-rouge">for&lt;'h, 'i, 'j&gt; T::Assoc&lt;'h, 'i, 'j&gt;: 'h</code> where clause:
1) Identify the outlived lifetime. If it is <code class="language-plaintext highlighter-rouge">'static</code>, there are no live lifetimes. If it is free, all lifetimes are live.
    - The outlived lifetime is <code class="language-plaintext highlighter-rouge">'h</code>.
2) For each param in the where clause for the associated type, if it matches the outlived lifetime then map it to the lifetime on the associated type.
    - <code class="language-plaintext highlighter-rouge">'h</code> in <code class="language-plaintext highlighter-rouge">T::Assoc&lt;'h, 'i, 'j&gt;</code> corresponds with <code class="language-plaintext highlighter-rouge">'a</code> on the associated type.
3) For each lifetime on the associated type that may be live, find the transitive params that could <em>also</em> be live.
    - This uses the generalized algorithm from steps 2-4 earlier.
    - Here, that expanded set is <code class="language-plaintext highlighter-rouge">'a</code> and <code class="language-plaintext highlighter-rouge">'b</code>.
4) Substitute the actual values.
    - For <code class="language-plaintext highlighter-rouge">T::Assoc&lt;'?1, '?2, '?3&gt;</code>, map <code class="language-plaintext highlighter-rouge">'a</code> =&gt; <code class="language-plaintext highlighter-rouge">'?1</code> and <code class="language-plaintext highlighter-rouge">'b</code> =&gt; <code class="language-plaintext highlighter-rouge">'?2</code>.</p>

<p>Simple enough, right?</p>

<p>What about when there are multiple where clauses?</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">fn9</span><span class="o">&lt;</span><span class="n">T</span><span class="p">:</span> <span class="n">MyTrait</span><span class="o">&gt;</span><span class="p">()</span> <span class="k">where</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'i</span><span class="p">,</span> <span class="nv">'j</span><span class="o">&gt;</span> <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'i</span><span class="p">,</span> <span class="nv">'j</span><span class="o">&gt;</span><span class="p">:</span> <span class="nv">'h</span><span class="p">,</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'i</span><span class="p">,</span> <span class="nv">'j</span><span class="o">&gt;</span> <span class="nn">T</span><span class="p">::</span><span class="n">Assoc</span><span class="o">&lt;</span><span class="nv">'h</span><span class="p">,</span> <span class="nv">'i</span><span class="p">,</span> <span class="nv">'j</span><span class="o">&gt;</span><span class="p">:</span> <span class="nv">'j</span><span class="p">,</span>
</code></pre></div></div>

<p>This answer <em>is</em> actually simple: each where clause <em>independently</em> restricts the set of live regions.</p>

<h3 id="putting-it-all-together">Putting it all together</h3>

<p>To reiterate and summarize the solution:</p>
<ul>
  <li>By default, all params substituted into an alias (either an associated type or an opaque) are treated as live</li>
  <li>Outlives bounds on either the definition or in each in-scope where clause each <em>independently</em> restrict the set of params that are treated as live</li>
  <li>The set of params treated as live is equal to the set of params that can outlive the outlives bound</li>
  <li>Outlives relationships for opaques are calculated using the parent function’s where clauses and well-formed inputs and output</li>
  <li>Outlives relationships for associated types are calculated using in-scope bounds</li>
</ul>

<h2 id="conclusions">Conclusions</h2>

<p>I’m hoping I didn’t lose you. This is complicated, and there are some nuances that I didn’t talk about (for example, free standing type aliases are <em>also</em> affected, albeit similar to associated types). <a href="https://github.com/rust-lang/rust/pull/156027">The PR</a> with this fix is up, if you’re curious to take a look. You might be interested to see some of the 8 new tests added that demonstrate the complexity (on top of the three existing ones), or read through the actual implementation (it’s hopefully commented well enough).</p>

<p>As a final point: calculating liveness correctly for associated types and opaque types does have positive consequences outside the borrow-checker. For example, there are <a href="https://github.com/rust-lang/rust/issues/42940">open issues</a> for where we incorrectly over-approximate live variables, because <a href="https://github.com/rust-lang/rust/pull/116040">attempting to be more correct</a> was clearly unsound. The fix presented here allows us to <em>properly</em> calculate liveness and allow <em>more</em> code to compile (correctly).</p>

<p>With all hope, this will be landed soon and Polonius Alpha will be on its way to stabilization!</p>]]></content><author><name></name></author><category term="rust" /><summary type="html"><![CDATA[If you’ve used Rust enough, you might have run into one or two limitations in the borrow checker. Maybe you tried to write a function like this, and got an error:]]></summary></entry><entry><title type="html">The Rust borrow checker just got (a little bit) smarter</title><link href="https://jackhuey.me/rust/2022/06/10/nll-stabilization.html" rel="alternate" type="text/html" title="The Rust borrow checker just got (a little bit) smarter" /><published>2022-06-10T15:00:00+00:00</published><updated>2022-06-10T15:00:00+00:00</updated><id>https://jackhuey.me/rust/2022/06/10/nll-stabilization</id><content type="html" xml:base="https://jackhuey.me/rust/2022/06/10/nll-stabilization.html"><![CDATA[<p>Well, at least, the NLL borrow checker finally got fully enabled by default - but that’s not as catchy of a title, is it?</p>

<p>Let’s start with the basics. What am I writing this post for? For a few reasons, actually. First, many lifetime errors have changed on nightly (and will hit stable in August), so I want to introduce them a bit, because I think they’re really cool. Second, I want to give a little history of how we got here, because I think it’s always important to look at things in retrospect. And third, along the way, I want to shout out all the work done by various contributors to get this enabled. I personally have done very little of the work here; I’m mostly going to be telling a story written by others, and they deserve all the credit.</p>

<p>Also note, while there are a handful of things that will now compile that didn’t before, I won’t really talk about them here. The list is small and most people won’t hit them. The <a href="https://github.com/rust-lang/rust/pull/95565">stabilization PR</a> has a couple examples.</p>

<p>I’ll start by just including a snippet of the stabilization report, which gives a brief summary of the motivation of this change, which might help frame the current text.</p>

<blockquote>
  <p>Over time, the Rust borrow checker has become “smarter” and thus allowed more programs to compile. There have been three different implementations: AST borrowck, MIR borrowck, and polonius (well, in progress). Additionally, there is the “lexical region resolver”, which (roughly) solves the constraints generated through HIR typeck. It is not a full borrow checker, but does emit some errors.
The AST borrowck was the original implementation of the borrow checker and was part of the initially stabilized Rust 1.0. In mid 2017, work began to implement the current MIR borrow checker and that effort ompleted by the end of 2017, for the most part. During 2018, efforts were made to migrate away from the AST borrow checker to the MIR borrow checker - eventually culminating into “migrate” mode - where HIR typeck with lexical region resolving following by MIR borrow checking - being active by default in the 2018 edition.
In early 2019, migrate mode was turned on by default in the 2015 edition as well, but with MIR borrowck errors emitted as warnings. By late 2019, these warnings were upgraded to full errors. This was followed by the complete removal of the AST borrow checker.
In the period since, various errors emitted by the MIR borrow checker have been improved to the point that they are mostly the same or better than those emitted by the lexical region resolver.
While there do remain some degradations in errors (tracked under the NLL-diagnostics tag, those are sufficiently small and rare enough that increased flexibility of MIR borrow check-only is now a worthwhile tradeoff.</p>
</blockquote>

<h1 id="error-changes">Error changes</h1>

<p>Likely the biggest difference that will be noticed after this change will be to the error messages you get regarding lifetime errors. To showcase some of the improvements, let me give a few examples. Ultimately, I won’t be able to give a comprehensive overview (there were over 900 rustc test files changed!), but hopefully these examples can provide some representation. For these examples, I’ll give a code snippet, the output on stable 1.61 and on the current nightly.</p>

<h2 id="lifetime-may-not-live-long-enough">Lifetime may not live long enough</h2>

<p>The first error change highlights nicely the difference in how the compiler processes lifetime errors before and after this change.</p>

<p>Given the following snippet:</p>

<pre><code class="language-rust=">fn transmute_lifetime&lt;'a, 'b, T&gt;(t: &amp;'a (T,)) -&gt; &amp;'b T {
    match (&amp;t,) {
        ((u,),) =&gt; u,
    }
}
fn main() {
  let y = Box::new((42,));
  let x = transmute_lifetime(&amp;y);
}
</code></pre>

<p>Stable emits the following error:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">error</span><span class="p">[</span><span class="n">E0495</span><span class="p">]:</span> <span class="n">cannot</span> <span class="n">infer</span> <span class="n">an</span> <span class="n">appropriate</span> <span class="n">lifetime</span> <span class="n">due</span> <span class="n">to</span> <span class="n">conflicting</span> <span class="n">requirements</span>
 <span class="o">-</span><span class="k">-&gt;</span> <span class="n">src</span><span class="o">/</span><span class="n">main</span><span class="py">.rs</span><span class="p">:</span><span class="mi">2</span><span class="p">:</span><span class="mi">11</span>
  <span class="p">|</span>
<span class="mi">2</span> <span class="p">|</span>     <span class="k">match</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">t</span><span class="p">,)</span> <span class="p">{</span>
  <span class="p">|</span>           <span class="o">^^^^^</span>
  <span class="p">|</span>
<span class="n">note</span><span class="p">:</span> <span class="n">first</span><span class="p">,</span> <span class="n">the</span> <span class="n">lifetime</span> <span class="n">cannot</span> <span class="n">outlive</span> <span class="n">the</span> <span class="n">lifetime</span> <span class="err">`</span><span class="nv">'a</span><span class="err">`</span> <span class="k">as</span> <span class="n">defined</span> <span class="n">here</span><span class="o">...</span>
 <span class="o">-</span><span class="k">-&gt;</span> <span class="n">src</span><span class="o">/</span><span class="n">main</span><span class="py">.rs</span><span class="p">:</span><span class="mi">1</span><span class="p">:</span><span class="mi">23</span>
  <span class="p">|</span>
<span class="mi">1</span> <span class="p">|</span> <span class="k">fn</span> <span class="n">transmute_lifetime</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">,</span> <span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">t</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="p">(</span><span class="n">T</span><span class="p">,))</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="nv">'b</span> <span class="n">T</span> <span class="p">{</span>
  <span class="p">|</span>                       <span class="o">^^</span>
<span class="n">note</span><span class="p">:</span> <span class="o">...</span><span class="n">so</span> <span class="n">that</span> <span class="n">the</span> <span class="n">types</span> <span class="n">are</span> <span class="n">compatible</span>
 <span class="o">-</span><span class="k">-&gt;</span> <span class="n">src</span><span class="o">/</span><span class="n">main</span><span class="py">.rs</span><span class="p">:</span><span class="mi">2</span><span class="p">:</span><span class="mi">11</span>
  <span class="p">|</span>
<span class="mi">2</span> <span class="p">|</span>     <span class="k">match</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">t</span><span class="p">,)</span> <span class="p">{</span>
  <span class="p">|</span>           <span class="o">^^^^^</span>
  <span class="o">=</span> <span class="n">note</span><span class="p">:</span> <span class="n">expected</span> <span class="err">`</span><span class="p">(</span><span class="o">&amp;&amp;</span><span class="p">(</span><span class="n">T</span><span class="p">,),)</span><span class="err">`</span>
             <span class="n">found</span> <span class="err">`</span><span class="p">(</span><span class="o">&amp;&amp;</span><span class="nv">'a</span> <span class="p">(</span><span class="n">T</span><span class="p">,),)</span><span class="err">`</span>
<span class="n">note</span><span class="p">:</span> <span class="n">but</span><span class="p">,</span> <span class="n">the</span> <span class="n">lifetime</span> <span class="n">must</span> <span class="n">be</span> <span class="n">valid</span> <span class="k">for</span> <span class="n">the</span> <span class="n">lifetime</span> <span class="err">`</span><span class="nv">'b</span><span class="err">`</span> <span class="k">as</span> <span class="n">defined</span> <span class="n">here</span><span class="o">...</span>
 <span class="o">-</span><span class="k">-&gt;</span> <span class="n">src</span><span class="o">/</span><span class="n">main</span><span class="py">.rs</span><span class="p">:</span><span class="mi">1</span><span class="p">:</span><span class="mi">27</span>
  <span class="p">|</span>
<span class="mi">1</span> <span class="p">|</span> <span class="k">fn</span> <span class="n">transmute_lifetime</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">,</span> <span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">t</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="p">(</span><span class="n">T</span><span class="p">,))</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="nv">'b</span> <span class="n">T</span> <span class="p">{</span>
  <span class="p">|</span>                           <span class="o">^^</span>
<span class="n">note</span><span class="p">:</span> <span class="o">...</span><span class="n">so</span> <span class="n">that</span> <span class="n">reference</span> <span class="n">does</span> <span class="n">not</span> <span class="n">outlive</span> <span class="n">borrowed</span> <span class="n">content</span>
 <span class="o">-</span><span class="k">-&gt;</span> <span class="n">src</span><span class="o">/</span><span class="n">main</span><span class="py">.rs</span><span class="p">:</span><span class="mi">3</span><span class="p">:</span><span class="mi">20</span>
  <span class="p">|</span>
<span class="mi">3</span> <span class="p">|</span>         <span class="p">((</span><span class="n">u</span><span class="p">,),)</span> <span class="k">=&gt;</span> <span class="n">u</span><span class="p">,</span>
  <span class="p">|</span>                    <span class="o">^</span>

<span class="n">For</span> <span class="n">more</span> <span class="n">information</span> <span class="n">about</span> <span class="n">this</span> <span class="n">error</span><span class="p">,</span> <span class="k">try</span> <span class="err">`</span><span class="n">rustc</span> <span class="o">--</span><span class="n">explain</span> <span class="n">E0495</span><span class="err">`.</span>
</code></pre></div></div>

<p>Note that the primary location of the error points at the scrutinee (<code class="language-plaintext highlighter-rouge">(&amp;t,)</code>) of the match. Also note that this error is pretty verbose and takes up a whopping 30 lines. On nightly:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">error</span><span class="p">:</span> <span class="n">lifetime</span> <span class="n">may</span> <span class="n">not</span> <span class="n">live</span> <span class="n">long</span> <span class="n">enough</span>
 <span class="o">-</span><span class="k">-&gt;</span> <span class="n">src</span><span class="o">/</span><span class="n">main</span><span class="py">.rs</span><span class="p">:</span><span class="mi">3</span><span class="p">:</span><span class="mi">20</span>
  <span class="p">|</span>
<span class="mi">1</span> <span class="p">|</span> <span class="k">fn</span> <span class="n">transmute_lifetime</span><span class="o">&lt;</span><span class="nv">'a</span><span class="p">,</span> <span class="nv">'b</span><span class="p">,</span> <span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">t</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="p">(</span><span class="n">T</span><span class="p">,))</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="nv">'b</span> <span class="n">T</span> <span class="p">{</span>
  <span class="p">|</span>                       <span class="o">--</span>  <span class="o">--</span> <span class="n">lifetime</span> <span class="err">`</span><span class="nv">'b</span><span class="err">`</span> <span class="n">defined</span> <span class="n">here</span>
  <span class="p">|</span>                       <span class="p">|</span>
  <span class="p">|</span>                       <span class="n">lifetime</span> <span class="err">`</span><span class="nv">'a</span><span class="err">`</span> <span class="n">defined</span> <span class="n">here</span>
<span class="mi">2</span> <span class="p">|</span>     <span class="k">match</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">t</span><span class="p">,)</span> <span class="p">{</span>
<span class="mi">3</span> <span class="p">|</span>         <span class="p">((</span><span class="n">u</span><span class="p">,),)</span> <span class="k">=&gt;</span> <span class="n">u</span><span class="p">,</span>
  <span class="p">|</span>                    <span class="o">^</span> <span class="n">function</span> <span class="n">was</span> <span class="n">supposed</span> <span class="n">to</span> <span class="k">return</span> <span class="n">data</span> <span class="n">with</span> <span class="n">lifetime</span> <span class="err">`</span><span class="nv">'b</span><span class="err">`</span> <span class="n">but</span> <span class="n">it</span> <span class="n">is</span> <span class="n">returning</span> <span class="n">data</span> <span class="n">with</span> <span class="n">lifetime</span> <span class="err">`</span><span class="nv">'a</span><span class="err">`</span>
  <span class="p">|</span>
  <span class="o">=</span> <span class="n">help</span><span class="p">:</span> <span class="n">consider</span> <span class="n">adding</span> <span class="n">the</span> <span class="n">following</span> <span class="n">bound</span><span class="p">:</span> <span class="err">`</span><span class="nv">'a</span><span class="p">:</span> <span class="nv">'b</span><span class="err">`</span>
</code></pre></div></div>

<p>This is quite different. First, it’s much more terse in output; only taking up 12 lines. Second, the error points primarily at <code class="language-plaintext highlighter-rouge">u</code>, which actually is what get returned by the match expression. Finally, we get an actual helpful suggestion to add the <code class="language-plaintext highlighter-rouge">'a: 'b</code> bound, which actually does fix this code. On the other hand, we do lose the “expected XX found XX” note, but it’s not super helpful in this case anyways. Also note that we lose the error code (E0495), which is unfortunate as this might be able to point the user to a more detained explanation.</p>

<p>Here’s a slightly different code snippet:</p>

<pre><code class="language-rust=">pub fn opt_str&lt;'a&gt;(maybestr: &amp;'a Option&lt;String&gt;) -&gt; &amp;'static str {
    if maybestr.is_none() {
        "(none)"
    } else {
        let s: &amp;'a str = maybestr.as_ref().unwrap();
        s
    }
}
</code></pre>

<p>The error on stable isn’t too bad and fairly straightforward:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">error</span><span class="p">[</span><span class="n">E0312</span><span class="p">]:</span> <span class="n">lifetime</span> <span class="n">of</span> <span class="n">reference</span> <span class="n">outlives</span> <span class="n">lifetime</span> <span class="n">of</span> <span class="n">borrowed</span> <span class="n">content</span><span class="o">...</span>
 <span class="o">-</span><span class="k">-&gt;</span> <span class="n">src</span><span class="o">/</span><span class="n">lib</span><span class="py">.rs</span><span class="p">:</span><span class="mi">6</span><span class="p">:</span><span class="mi">9</span>
  <span class="p">|</span>
<span class="mi">6</span> <span class="p">|</span>         <span class="n">s</span>
  <span class="p">|</span>         <span class="o">^</span>
  <span class="p">|</span>
  <span class="o">=</span> <span class="n">note</span><span class="p">:</span> <span class="o">...</span><span class="n">the</span> <span class="n">reference</span> <span class="n">is</span> <span class="n">valid</span> <span class="k">for</span> <span class="n">the</span> <span class="k">static</span> <span class="n">lifetime</span><span class="o">...</span>
<span class="n">note</span><span class="p">:</span> <span class="o">...</span><span class="n">but</span> <span class="n">the</span> <span class="n">borrowed</span> <span class="n">content</span> <span class="n">is</span> <span class="n">only</span> <span class="n">valid</span> <span class="k">for</span> <span class="n">the</span> <span class="n">lifetime</span> <span class="err">`</span><span class="nv">'a</span><span class="err">`</span> <span class="k">as</span> <span class="n">defined</span> <span class="n">here</span>
 <span class="o">-</span><span class="k">-&gt;</span> <span class="n">src</span><span class="o">/</span><span class="n">lib</span><span class="py">.rs</span><span class="p">:</span><span class="mi">1</span><span class="p">:</span><span class="mi">16</span>
  <span class="p">|</span>
<span class="mi">1</span> <span class="p">|</span> <span class="k">pub</span> <span class="k">fn</span> <span class="n">opt_str</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">(</span><span class="n">maybestr</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span> <span class="p">{</span>
  <span class="p">|</span>                <span class="o">^^</span>

<span class="n">For</span> <span class="n">more</span> <span class="n">information</span> <span class="n">about</span> <span class="n">this</span> <span class="n">error</span><span class="p">,</span> <span class="k">try</span> <span class="err">`</span><span class="n">rustc</span> <span class="o">--</span><span class="n">explain</span> <span class="n">E0312</span><span class="err">`.</span>
</code></pre></div></div>

<p>And on nightly:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">error</span><span class="p">:</span> <span class="n">lifetime</span> <span class="n">may</span> <span class="n">not</span> <span class="n">live</span> <span class="n">long</span> <span class="n">enough</span>
 <span class="o">-</span><span class="k">-&gt;</span> <span class="n">src</span><span class="o">/</span><span class="n">lib</span><span class="py">.rs</span><span class="p">:</span><span class="mi">6</span><span class="p">:</span><span class="mi">9</span>
  <span class="p">|</span>
<span class="mi">1</span> <span class="p">|</span> <span class="k">pub</span> <span class="k">fn</span> <span class="n">opt_str</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">(</span><span class="n">maybestr</span><span class="p">:</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="o">&amp;</span><span class="k">'static</span> <span class="nb">str</span> <span class="p">{</span>
  <span class="p">|</span>                <span class="o">--</span> <span class="n">lifetime</span> <span class="err">`</span><span class="nv">'a</span><span class="err">`</span> <span class="n">defined</span> <span class="n">here</span>
<span class="o">...</span>
<span class="mi">6</span> <span class="p">|</span>         <span class="n">s</span>
  <span class="p">|</span>         <span class="o">^</span> <span class="n">returning</span> <span class="n">this</span> <span class="n">value</span> <span class="n">requires</span> <span class="n">that</span> <span class="err">`</span><span class="nv">'a</span><span class="err">`</span> <span class="n">must</span> <span class="n">outlive</span> <span class="err">`</span><span class="k">'static</span><span class="err">`</span>
</code></pre></div></div>

<p>We give all the same infomration in a slightly shorter error. We also lose the error code (E0312), which again is unfortunate. As you might notice though, what were two very different error outputs before look a bit more similar now: we do slightly less arbibtrary grouping.</p>

<h2 id="borrowed-data-escapes-function">Borrowed data escapes function</h2>

<p>This next error is a little less straightforward. In fact, this is a case we actually regress a bit, but not <em>too</em> bad.</p>

<pre><code class="language-rust=">use std::sync::Mutex;
struct MyString&lt;'a&gt; {
    data: &amp;'a str,
}
fn i_want_static_closure&lt;F&gt;(a: F)
where
    F: Fn() + 'static,
{
}
fn print_string&lt;'a&gt;(s: Mutex&lt;MyString&lt;'a&gt;&gt;) {
    i_want_static_closure(move || {
        println!("{}", s.lock().unwrap().data);
    });
}
</code></pre>

<p>Before I show the errors, let me just say: there’s a lot going on here. However, the crux of the error is the <code class="language-plaintext highlighter-rouge">'static'</code> bound on <code class="language-plaintext highlighter-rouge">F</code> on line 7. So…stable:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">error</span><span class="p">[</span><span class="n">E0477</span><span class="p">]:</span> <span class="n">the</span> <span class="k">type</span> <span class="err">`</span><span class="p">[</span><span class="n">closure</span><span class="o">@</span><span class="n">src</span><span class="o">/</span><span class="n">lib</span><span class="py">.rs</span><span class="p">:</span><span class="mi">11</span><span class="p">:</span><span class="mi">27</span><span class="p">:</span> <span class="mi">13</span><span class="p">:</span><span class="mi">6</span><span class="p">]</span><span class="err">`</span> <span class="n">does</span> <span class="n">not</span> <span class="n">fulfill</span> <span class="n">the</span> <span class="n">required</span> <span class="n">lifetime</span>
  <span class="o">-</span><span class="k">-&gt;</span> <span class="n">src</span><span class="o">/</span><span class="n">lib</span><span class="py">.rs</span><span class="p">:</span><span class="mi">11</span><span class="p">:</span><span class="mi">5</span>
   <span class="p">|</span>
<span class="mi">11</span> <span class="p">|</span>     <span class="nf">i_want_static_closure</span><span class="p">(</span><span class="k">move</span> <span class="p">||</span> <span class="p">{</span>
   <span class="p">|</span>     <span class="o">^^^^^^^^^^^^^^^^^^^^^</span>
   <span class="p">|</span>
<span class="n">note</span><span class="p">:</span> <span class="k">type</span> <span class="n">must</span> <span class="n">satisfy</span> <span class="n">the</span> <span class="k">static</span> <span class="n">lifetime</span> <span class="k">as</span> <span class="n">required</span> <span class="n">by</span> <span class="n">this</span> <span class="n">binding</span>
  <span class="o">-</span><span class="k">-&gt;</span> <span class="n">src</span><span class="o">/</span><span class="n">lib</span><span class="py">.rs</span><span class="p">:</span><span class="mi">7</span><span class="p">:</span><span class="mi">15</span>
   <span class="p">|</span>
<span class="mi">7</span>  <span class="p">|</span>     <span class="n">F</span><span class="p">:</span> <span class="nf">Fn</span><span class="p">()</span> <span class="o">+</span> <span class="k">'static</span><span class="p">,</span>
   <span class="p">|</span>               <span class="o">^^^^^^^</span>

<span class="n">For</span> <span class="n">more</span> <span class="n">information</span> <span class="n">about</span> <span class="n">this</span> <span class="n">error</span><span class="p">,</span> <span class="k">try</span> <span class="err">`</span><span class="n">rustc</span> <span class="o">--</span><span class="n">explain</span> <span class="n">E0477</span><span class="err">`.</span>
</code></pre></div></div>

<p>Okay, great. This is exactly what we want: The closure is a problem, and it’s because we don’t satisfy that <code class="language-plaintext highlighter-rouge">'static'</code> bound. Nightly:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">error</span><span class="p">[</span><span class="n">E0521</span><span class="p">]:</span> <span class="n">borrowed</span> <span class="n">data</span> <span class="n">escapes</span> <span class="n">outside</span> <span class="n">of</span> <span class="n">function</span>
  <span class="o">-</span><span class="k">-&gt;</span> <span class="n">src</span><span class="o">/</span><span class="n">lib</span><span class="py">.rs</span><span class="p">:</span><span class="mi">11</span><span class="p">:</span><span class="mi">5</span>
   <span class="p">|</span>
<span class="mi">10</span> <span class="p">|</span>   <span class="k">fn</span> <span class="n">print_string</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">(</span><span class="n">s</span><span class="p">:</span> <span class="n">Mutex</span><span class="o">&lt;</span><span class="n">MyString</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;&gt;</span><span class="p">)</span> <span class="p">{</span>
   <span class="p">|</span>                   <span class="o">--</span>  <span class="o">-</span> <span class="err">`</span><span class="n">s</span><span class="err">`</span> <span class="n">is</span> <span class="n">a</span> <span class="n">reference</span> <span class="n">that</span> <span class="n">is</span> <span class="n">only</span> <span class="n">valid</span> <span class="k">in</span> <span class="n">the</span> <span class="n">function</span> <span class="n">body</span>
   <span class="p">|</span>                   <span class="p">|</span>
   <span class="p">|</span>                   <span class="n">lifetime</span> <span class="err">`</span><span class="nv">'a</span><span class="err">`</span> <span class="n">defined</span> <span class="n">here</span>
<span class="mi">11</span> <span class="p">|</span> <span class="o">/</span>     <span class="nf">i_want_static_closure</span><span class="p">(</span><span class="k">move</span> <span class="p">||</span> <span class="p">{</span>
<span class="mi">12</span> <span class="p">|</span> <span class="p">|</span>         <span class="nd">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span> <span class="n">s</span><span class="nf">.lock</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">()</span><span class="py">.data</span><span class="p">);</span>
<span class="mi">13</span> <span class="p">|</span> <span class="p">|</span>     <span class="p">});</span>
   <span class="p">|</span> <span class="p">|</span>      <span class="o">^</span>
   <span class="p">|</span> <span class="p">|</span>      <span class="p">|</span>
   <span class="p">|</span> <span class="p">|</span><span class="n">______</span><span class="err">`</span><span class="n">s</span><span class="err">`</span> <span class="n">escapes</span> <span class="n">the</span> <span class="n">function</span> <span class="n">body</span> <span class="n">here</span>
   <span class="p">|</span>        <span class="n">argument</span> <span class="n">requires</span> <span class="n">that</span> <span class="err">`</span><span class="nv">'a</span><span class="err">`</span> <span class="n">must</span> <span class="n">outlive</span> <span class="err">`</span><span class="k">'static</span><span class="err">`</span>
   <span class="p">|</span>
   <span class="o">=</span> <span class="n">note</span><span class="p">:</span> <span class="n">requirement</span> <span class="n">occurs</span> <span class="n">because</span> <span class="n">of</span> <span class="n">the</span> <span class="k">type</span> <span class="err">`</span><span class="n">Mutex</span><span class="o">&lt;</span><span class="n">MyString</span><span class="o">&lt;</span><span class="nv">'_</span><span class="o">&gt;&gt;</span><span class="err">`</span><span class="p">,</span> <span class="n">which</span> <span class="n">makes</span> <span class="n">the</span> <span class="n">generic</span> <span class="n">argument</span> <span class="err">`</span><span class="n">MyString</span><span class="o">&lt;</span><span class="nv">'_</span><span class="o">&gt;</span><span class="err">`</span> <span class="n">invariant</span>
   <span class="o">=</span> <span class="n">note</span><span class="p">:</span> <span class="n">the</span> <span class="k">struct</span> <span class="err">`</span><span class="n">Mutex</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="err">`</span> <span class="n">is</span> <span class="n">invariant</span> <span class="n">over</span> <span class="n">the</span> <span class="n">parameter</span> <span class="err">`</span><span class="n">T</span><span class="err">`</span>
   <span class="o">=</span> <span class="n">help</span><span class="p">:</span> <span class="n">see</span> <span class="o">&lt;</span><span class="n">https</span><span class="p">:</span><span class="c1">//doc.rust-lang.org/nomicon/subtyping.html&gt; for more information about variance</span>

<span class="n">For</span> <span class="n">more</span> <span class="n">information</span> <span class="n">about</span> <span class="n">this</span> <span class="n">error</span><span class="p">,</span> <span class="k">try</span> <span class="err">`</span><span class="n">rustc</span> <span class="o">--</span><span class="n">explain</span> <span class="n">E0521</span><span class="err">`.</span>
</code></pre></div></div>

<p>Well…this isn’t great. We at least get the “<code class="language-plaintext highlighter-rouge">'a</code> must outlive <code class="language-plaintext highlighter-rouge">'static</code>”, which might give some clue to the problem. But, we also get a couple notes about variance. This is not really helpful here - it doesn’t have any effect on the error (even though it <em>is</em> true).</p>

<h2 id="helpful-variance-note">Helpful variance note</h2>

<p>Okay, let’s pick out an error that actually does stem from variance and how it has changed. We’ll have this be the last one.</p>

<pre><code class="language-rust=">struct SomeStruct&lt;T&gt;(*mut T);

fn foo&lt;'min, 'max: 'min&gt;(v: SomeStruct&lt;&amp;'max ()&gt;) -&gt; SomeStruct&lt;&amp;'min ()&gt; {
    v
}
</code></pre>

<p>Just quickly, I want to point out the <code class="language-plaintext highlighter-rouge">*mut T</code> in <code class="language-plaintext highlighter-rouge">SomeStruct</code>. If this was only <code class="language-plaintext highlighter-rouge">T</code>, this snippet wouldn’t have any problem. See if you can find out why from the errors (I did give a hint above). On stable:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">error</span><span class="p">[</span><span class="n">E0308</span><span class="p">]:</span> <span class="n">mismatched</span> <span class="n">types</span>
 <span class="o">-</span><span class="k">-&gt;</span> <span class="n">src</span><span class="o">/</span><span class="n">lib</span><span class="py">.rs</span><span class="p">:</span><span class="mi">4</span><span class="p">:</span><span class="mi">5</span>
  <span class="p">|</span>
<span class="mi">4</span> <span class="p">|</span>     <span class="n">v</span>
  <span class="p">|</span>     <span class="o">^</span> <span class="n">lifetime</span> <span class="n">mismatch</span>
  <span class="p">|</span>
  <span class="o">=</span> <span class="n">note</span><span class="p">:</span> <span class="n">expected</span> <span class="k">struct</span> <span class="err">`</span><span class="n">SomeStruct</span><span class="o">&lt;&amp;</span><span class="nv">'min</span> <span class="p">()</span><span class="o">&gt;</span><span class="err">`</span>
             <span class="n">found</span> <span class="k">struct</span> <span class="err">`</span><span class="n">SomeStruct</span><span class="o">&lt;&amp;</span><span class="nv">'max</span> <span class="p">()</span><span class="o">&gt;</span><span class="err">`</span>
<span class="n">note</span><span class="p">:</span> <span class="n">the</span> <span class="n">lifetime</span> <span class="err">`</span><span class="nv">'min</span><span class="err">`</span> <span class="k">as</span> <span class="n">defined</span> <span class="n">here</span><span class="o">...</span>
 <span class="o">-</span><span class="k">-&gt;</span> <span class="n">src</span><span class="o">/</span><span class="n">lib</span><span class="py">.rs</span><span class="p">:</span><span class="mi">3</span><span class="p">:</span><span class="mi">8</span>
  <span class="p">|</span>
<span class="mi">3</span> <span class="p">|</span> <span class="k">fn</span> <span class="n">foo</span><span class="o">&lt;</span><span class="nv">'min</span><span class="p">,</span> <span class="nv">'max</span><span class="p">:</span> <span class="nv">'min</span><span class="o">&gt;</span><span class="p">(</span><span class="n">v</span><span class="p">:</span> <span class="n">SomeStruct</span><span class="o">&lt;&amp;</span><span class="nv">'max</span> <span class="p">()</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">SomeStruct</span><span class="o">&lt;&amp;</span><span class="nv">'min</span> <span class="p">()</span><span class="o">&gt;</span> <span class="p">{</span>
  <span class="p">|</span>        <span class="o">^^^^</span>
<span class="n">note</span><span class="p">:</span> <span class="o">...</span><span class="n">does</span> <span class="n">not</span> <span class="n">necessarily</span> <span class="n">outlive</span> <span class="n">the</span> <span class="n">lifetime</span> <span class="err">`</span><span class="nv">'max</span><span class="err">`</span> <span class="k">as</span> <span class="n">defined</span> <span class="n">here</span>
 <span class="o">-</span><span class="k">-&gt;</span> <span class="n">src</span><span class="o">/</span><span class="n">lib</span><span class="py">.rs</span><span class="p">:</span><span class="mi">3</span><span class="p">:</span><span class="mi">14</span>
  <span class="p">|</span>
<span class="mi">3</span> <span class="p">|</span> <span class="k">fn</span> <span class="n">foo</span><span class="o">&lt;</span><span class="nv">'min</span><span class="p">,</span> <span class="nv">'max</span><span class="p">:</span> <span class="nv">'min</span><span class="o">&gt;</span><span class="p">(</span><span class="n">v</span><span class="p">:</span> <span class="n">SomeStruct</span><span class="o">&lt;&amp;</span><span class="nv">'max</span> <span class="p">()</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">SomeStruct</span><span class="o">&lt;&amp;</span><span class="nv">'min</span> <span class="p">()</span><span class="o">&gt;</span> <span class="p">{</span>
  <span class="p">|</span>              <span class="o">^^^^</span>

<span class="n">For</span> <span class="n">more</span> <span class="n">information</span> <span class="n">about</span> <span class="n">this</span> <span class="n">error</span><span class="p">,</span> <span class="k">try</span> <span class="err">`</span><span class="n">rustc</span> <span class="o">--</span><span class="n">explain</span> <span class="n">E0308</span><span class="err">`.</span>
</code></pre></div></div>

<p>So…this error is <em>okay</em>. We get told that we’re expecting <code class="language-plaintext highlighter-rouge">SomeStruct&lt;&amp;'min ()&gt;</code> and that <code class="language-plaintext highlighter-rouge">'min</code> doesn’t outlive <code class="language-plaintext highlighter-rouge">'max</code>. But we don’t really know <em>why</em>. There’s an error code, but it’s pretty generic. Let’s look at nightly:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">error</span><span class="p">:</span> <span class="n">lifetime</span> <span class="n">may</span> <span class="n">not</span> <span class="n">live</span> <span class="n">long</span> <span class="n">enough</span>
 <span class="o">-</span><span class="k">-&gt;</span> <span class="n">src</span><span class="o">/</span><span class="n">lib</span><span class="py">.rs</span><span class="p">:</span><span class="mi">4</span><span class="p">:</span><span class="mi">5</span>
  <span class="p">|</span>
<span class="mi">3</span> <span class="p">|</span> <span class="k">fn</span> <span class="n">foo</span><span class="o">&lt;</span><span class="nv">'min</span><span class="p">,</span> <span class="nv">'max</span><span class="p">:</span> <span class="nv">'min</span><span class="o">&gt;</span><span class="p">(</span><span class="n">v</span><span class="p">:</span> <span class="n">SomeStruct</span><span class="o">&lt;&amp;</span><span class="nv">'max</span> <span class="p">()</span><span class="o">&gt;</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">SomeStruct</span><span class="o">&lt;&amp;</span><span class="nv">'min</span> <span class="p">()</span><span class="o">&gt;</span> <span class="p">{</span>
  <span class="p">|</span>        <span class="o">----</span>  <span class="o">----</span> <span class="n">lifetime</span> <span class="err">`</span><span class="nv">'max</span><span class="err">`</span> <span class="n">defined</span> <span class="n">here</span>
  <span class="p">|</span>        <span class="p">|</span>
  <span class="p">|</span>        <span class="n">lifetime</span> <span class="err">`</span><span class="nv">'min</span><span class="err">`</span> <span class="n">defined</span> <span class="n">here</span>
<span class="mi">4</span> <span class="p">|</span>     <span class="n">v</span>
  <span class="p">|</span>     <span class="o">^</span> <span class="n">function</span> <span class="n">was</span> <span class="n">supposed</span> <span class="n">to</span> <span class="k">return</span> <span class="n">data</span> <span class="n">with</span> <span class="n">lifetime</span> <span class="err">`</span><span class="nv">'max</span><span class="err">`</span> <span class="n">but</span> <span class="n">it</span> <span class="n">is</span> <span class="n">returning</span> <span class="n">data</span> <span class="n">with</span> <span class="n">lifetime</span> <span class="err">`</span><span class="nv">'min</span><span class="err">`</span>
  <span class="p">|</span>
  <span class="o">=</span> <span class="n">help</span><span class="p">:</span> <span class="n">consider</span> <span class="n">adding</span> <span class="n">the</span> <span class="n">following</span> <span class="n">bound</span><span class="p">:</span> <span class="err">`</span><span class="nv">'min</span><span class="p">:</span> <span class="nv">'max</span><span class="err">`</span>
  <span class="o">=</span> <span class="n">note</span><span class="p">:</span> <span class="n">requirement</span> <span class="n">occurs</span> <span class="n">because</span> <span class="n">of</span> <span class="n">the</span> <span class="k">type</span> <span class="err">`</span><span class="n">SomeStruct</span><span class="o">&lt;&amp;</span><span class="p">()</span><span class="o">&gt;</span><span class="err">`</span><span class="p">,</span> <span class="n">which</span> <span class="n">makes</span> <span class="n">the</span> <span class="n">generic</span> <span class="n">argument</span> <span class="err">`</span><span class="o">&amp;</span><span class="p">()</span><span class="err">`</span> <span class="n">invariant</span>
  <span class="o">=</span> <span class="n">note</span><span class="p">:</span> <span class="n">the</span> <span class="k">struct</span> <span class="err">`</span><span class="n">SomeStruct</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="err">`</span> <span class="n">is</span> <span class="n">invariant</span> <span class="n">over</span> <span class="n">the</span> <span class="n">parameter</span> <span class="err">`</span><span class="n">T</span><span class="err">`</span>
  <span class="o">=</span> <span class="n">help</span><span class="p">:</span> <span class="n">see</span> <span class="o">&lt;</span><span class="n">https</span><span class="p">:</span><span class="c1">//doc.rust-lang.org/nomicon/subtyping.html&gt; for more information about variance</span>
</code></pre></div></div>

<p>Wow, that has a lot more information (and it’s also a bit more terse). And we get a suggestion (that works)! Does this help you understand why the code snippet is problematic? We can’t substitute <code class="language-plaintext highlighter-rouge">SomeStruct&lt;&amp;'max ()&gt;</code> for <code class="language-plaintext highlighter-rouge">SomeStruct&lt;&amp;'min ()&gt;</code> in the return type, because <code class="language-plaintext highlighter-rouge">T</code> is invariant. If <code class="language-plaintext highlighter-rouge">T</code> was covariant, we could.</p>

<h2 id="recap">Recap</h2>

<p>I’m not sure if this was too much - or too little. It’s also most just pasting a few code snippets and their errors, with a bit of commentary. Hopefully it at least scratches the surface of the types of lifetime error differences you might see on nightly compared to stable. If you’re interested in checking out how lifetime errors in rustc test suite have changed, feel free to check out the <a href="https://github.com/rust-lang/rust/pull/95565/files">PR</a> or take a look at the short list of <a href="https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3ANLL-diagnostics">diagnostic regressions</a>.</p>

<h1 id="how-did-we-get-here">How did we get here?</h1>

<p>So, for this section, I’m going to work backwards. This is primarily because it’s just easier to recall recent work than older work. I want to just briefly point out some of the major stepping stones towards this stabilization and shout out the various contributors that pushed to make this happen.</p>

<h2 id="triaging-diagnostic-changes-and-preparing-for-stabilization">Triaging diagnostic changes and preparing for stabilization</h2>

<p>The <a href="https://github.com/rust-lang/rust/pull/95565">stabilization PR</a> had 985 changed files. Most of those were test-related. It’s impractical to expect a reviewer to go through all of those changes and “sign off” on them all. Adding to that, with the way the rustc test suite is set up, changing test error output requires some manual intervention, so it would be helpful to make such a <em>big</em> PR be as mechanical as possible.</p>

<p>Over the past couple months <a href="https://github.com/marmeladema">@marmeladema</a> and I have worked to <a href="https://github.com/rust-lang/rust/pull/95591">go</a> <a href="https://github.com/rust-lang/rust/pull/96148">through</a> <a href="https://github.com/rust-lang/rust/pull/96212">all</a> <a href="https://github.com/rust-lang/rust/pull/97258">the</a> test error differences, file <a href="https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3ANLL-diagnostics">issues</a> for those where diagnostics have regressed (subjectively), and prepare the tests for a purely mechanical stabilization PR.</p>

<p><a href="https://github.com/m-ou-se">@m-ou-se</a> also triaged the crater run for the stabilization PR to give the stabilization a clean bill of health.</p>

<h2 id="tying-up-loose-ends">Tying up loose ends</h2>

<p>There are three parts to this.</p>

<p>First, <a href="https://github.com/marmeladema">@marmeladema</a> and <a href="https://github.com/Aaron1011">@Aaron1011</a> made some great PRs over the <a href="https://github.com/rust-lang/rust/pull/96409">last</a> <a href="https://github.com/rust-lang/rust/pull/96385">couple</a> <a href="https://github.com/rust-lang/rust/pull/96352">months</a> <a href="https://github.com/rust-lang/rust/pull/96236">to</a> reduce the number of diagnostic regressions.</p>

<p>Second, one of the last “big questions” prior to this stabilization was regarding to <a href="https://github.com/rust-lang/rust/issues/59159"><code class="language-plaintext highlighter-rouge">mutable_borrow_reservation_conflict</code> lint</a> (this actually came up in the crater run mentioned above). Without going into details, there were concerns that allowing the linted pattern would disallow some optimizations. It accidentally got stabilized in Rust 2018 and the thought was maybe to disallow it after full NLL stabilization. The lang team decided against this and the lint was removed.</p>

<p>Finally, the last bit of known behavior difference with the full stabilization concerned coercion with match statements and the <a href="https://github.com/rust-lang/rust/issues/73154">order of match expressions</a>. Actually, in migrate mode, the coercion here fails. Fully enabling NLL allows the pattern to compile, but only in one ordering. While we do want the coercion to compile eventually, we chose for now to just fallback to migrate mode behavior of <a href="https://github.com/rust-lang/rust/pull/97206">disallowing the coercion in either ordering</a>.</p>

<h2 id="huge-diagnostic-overhaul">Huge diagnostic overhaul</h2>

<p>Up until mid last year, progress on enabling NLL had mostly stalled. The biggest and most daunting blocker being a slew of hideus and generic “higher-ranked subtype error” for a large number of lifetime errors. <a href="https://github.com/matthewjasper">@matthewjasper</a> did some fantastic work in a branch that <a href="https://github.com/lqd">@lqd</a> rebased and made a <a href="https://github.com/rust-lang/rust/pull/86700">PR</a> for. It didn’t solve all the errors, but it provided a framework to solve most of the remaining problems. <a href="https://github.com/lqd">@lqd</a> followed up with another <a href="https://github.com/rust-lang/rust/pull/88270">PR</a> which fixed more diagnostics.</p>

<p>Then, <a href="https://github.com/Aaron1011">@Aaron1011</a> <a href="https://github.com/rust-lang/rust/pull/88708">made</a> <a href="https://github.com/rust-lang/rust/pull/89028">a</a> <a href="https://github.com/rust-lang/rust/pull/89110">long</a> <a href="https://github.com/rust-lang/rust/pull/89250">series</a> <a href="https://github.com/rust-lang/rust/pull/89249">of</a> <a href="https://github.com/rust-lang/rust/pull/89336">PRs</a> <a href="https://github.com/rust-lang/rust/pull/89504">addressing</a> <a href="https://github.com/rust-lang/rust/pull/89501">various</a> <a href="https://github.com/rust-lang/rust/pull/92306">diagnostics</a>. At this point, NLL was very close to being “ready” and just needed a few loose ends tied up.</p>

<h2 id="enabling-migrate-mode-and-removing-ast-borrowck">Enabling migrate mode and removing AST borrowck</h2>

<p>In 2018, migrate mode was <a href="https://github.com/rust-lang/rust/pull/52681">added and enabled</a> for the Rust 2018 edition by <a href="https://github.com/pnkfelix">@pnkfelix</a>. However, if code was rejected by NLL, but allowed by the AST borrowck, issues were only emitted as warnings. <a href="https://github.com/spastorino">@spastorino</a> also <a href="https://github.com/rust-lang/rust/pull/52083">made</a> the AST borrowck not run at all under <code class="language-plaintext highlighter-rouge">feature(nll)</code>.</p>

<p>Over the period of 2019, lots of shifting happening in the migration from the AST borrowck to the MIR borrowck (NLL). In March, <a href="https://github.com/matthewjasper">@matthewjasper</a> <a href="https://github.com/rust-lang/rust/pull/59114">enabled</a> migrate mode in Rust 2015, but with warning emitted instead of errors. <a href="https://github.com/chrisvittal">@chrisvittal</a> <a href="https://github.com/rust-lang/rust/pull/60513">removed</a> the mostly unused <code class="language-plaintext highlighter-rouge">-Zborrowck=compare</code> flag. Then <a href="https://github.com/Centril">@Centril</a> made a <a href="https://github.com/rust-lang/rust/pull/63565">series</a> <a href="https://github.com/rust-lang/rust/pull/64221">of</a> <a href="https://github.com/rust-lang/rust/pull/64790">PRs</a> that upgraded migrate mode NLL warnings to errors in Rust 2018 and Rust 2015, then finally removed the unused AST borrowck.</p>

<h2 id="nll-implementation">NLL implementation</h2>

<p>In the latter half of 2017 and into 2018, work was done to implement the MIR borrowck and bring it to feature and performance parity. <a href="https://github.com/nikomatsakis">@nikomatsakis</a> <a href="https://github.com/rust-lang/rfcs/pull/2094">envisioned</a> most of the borrow checker and did a large portion of the <a href="https://github.com/rust-lang/rfcs/pull/2094">implementation</a> <a href="https://github.com/rust-lang/rust/pull/46862">work</a>. However <a href="https://github.com/Nashenas88">@Nashenas88</a> made <a href="https://github.com/rust-lang/rust/pull/43271">a</a> <a href="https://github.com/rust-lang/rust/pull/43324">few</a> <a href="https://github.com/rust-lang/rust/pull/43559">PRs</a> to prepare the compiler for Niko’s branch. <a href="https://github.com/pnkfelix">@pnkfelix</a> and <a href="https://github.com/shepmaster">@shepmaster</a> did great work tracking progress. <a href="https://github.com/nnethercote">@nnethercote</a> did some amazing work <a href="https://blog.mozilla.org/nnethercote/2018/11/06/how-to-speed-up-the-rust-compiler-in-2018-nll-edition/">speeding up the implementation</a>. It’s very possible I’ve missed more, so if you see someone missing from this list, please DM me and I’ll correct it.</p>

<h1 id="summary">Summary</h1>

<p>That basically concludes this post. As always, this turned out a bit different from how I imagined it in my mind. But I do think it’s important to recount the history of the implementation and give credit to those that did the work to get where we are today. As a side effect, maybe a few people might find it interesting or get some use from going over a couple lifetime error differences.</p>

<p>As a side note, I do welcome feedback on these. I tend to make my blog posts more “informal” and “prose-like”, versus a more rigid structure. The downside of this is that they can be less “beginner-friendly”, in a sense. I would love to know if people enjoy these or not.</p>]]></content><author><name></name></author><category term="rust" /><summary type="html"><![CDATA[Well, at least, the NLL borrow checker finally got fully enabled by default - but that’s not as catchy of a title, is it?]]></summary></entry><entry><title type="html">A shiny future with GATs</title><link href="https://jackhuey.me/rust/2022/05/04/a-shiny-future-with-gats.html" rel="alternate" type="text/html" title="A shiny future with GATs" /><published>2022-05-04T14:30:00+00:00</published><updated>2022-05-04T14:30:00+00:00</updated><id>https://jackhuey.me/rust/2022/05/04/a-shiny-future-with-gats</id><content type="html" xml:base="https://jackhuey.me/rust/2022/05/04/a-shiny-future-with-gats.html"><![CDATA[<p>This was a surprisingly difficult blog post to write. Between general life things getting in the way and feeling a bit of lost steam, this took much longer than I expected.</p>

<p>Before I go further, if you don’t know what GATs (generic associated types) are, then I recommend reading <a href="https://blog.rust-lang.org/2021/08/03/GATs-stabilization-push.html">this blog post</a> from August of last year.</p>

<p>A bit over <a href="https://github.com/rust-lang/rust/issues/44265#issuecomment-775423925">a year ago</a>, the traits working group started to talk seriously about stabilizing GATs. I and others worked to close issues and move that forward. In <a href="https://github.com/rust-lang/rust/issues/44265#issuecomment-869888398">June last year</a>, I estimated October for stabilization. Well, turns out there were some things that we needed to do first (besides fixing bugs), like <a href="https://github.com/rust-lang/rust/pull/89970">implementing an outlives lint</a> and <a href="https://github.com/rust-lang/rust/pull/90076">changing the location of where clauses on GATs</a>. <a href="https://github.com/rust-lang/rust/issues/44265#issuecomment-990287168">In December</a>, once again, I said “we’re close.” Around Feburary or <a href="https://github.com/rust-lang/rust/issues/44265#issuecomment-1066173042">March</a>, we felt like we were finally in a place to stabilize. Except for one <em>small</em> thing: this blog post.</p>

<p>The goal of this blog post is to try to imagine a “shiny future” where we have GATs. It’s to consider a couple of the patterns that people want GATs for, how we might want to integrate GATs into standard library traits, and a few issues that don’t work <em>today</em> that we want to work in the future. We want this so that we have a future to strive for after stabilization. There are known shortcomings with GATs right now, but that’s okay. They’re already powerful and, as you’ll see, we have some thoughts on how to make them more powerful and ergonomic in the future.</p>

<p>Like I said, it’s been hard to write this. Partially because it’s <em>a lot</em>, but also because it’s difficult to think about the future and try to consider the intersection of a several different patterns. This isn’t to say that I alone have come up with these thoughts: much of this has been talked about within the traits working group. A huge shoutout to Niko Matsakis for an unenumerable amount of feedback, banter, and guidance.</p>

<p>Well, I’ve finally finished this post. To go with this, I’ve posted a <a href="https://github.com/rust-lang/rust/pull/96709">stabilization PR</a> for GATs to Github. It’s happening, y’all.</p>

<h2 id="getting-our-feet-wet-with-higher-kinded-types">Getting our feet wet with higher-kinded types</h2>

<p>To start with, I want to cover a pattern involving traits with GATs more-or-less representing the “Self” type. I’ll start by introducing two separate but related examples. After I introduce them, I’ll explain a bit about how they are similiar. Finally, I’ll discuss a bit how a full “higher-kinded types” feature might solve this.</p>

<h3 id="introducing-the-examples">Introducing the examples</h3>

<p>The first example roughly follows the <code class="language-plaintext highlighter-rouge">Collection</code> trait <a href="http://smallcultfollowing.com/babysteps/blog/2016/11/03/associated-type-constructors-part-2-family-traits/">introduced</a> by Niko Matsakis in a series of blog posts in 2016. Here I’ve made two changes. First, the type parameter <code class="language-plaintext highlighter-rouge">T</code> on <code class="language-plaintext highlighter-rouge">Collection</code> has been changed to an associated type - which more closely matches real collections like <code class="language-plaintext highlighter-rouge">Vec</code> or <code class="language-plaintext highlighter-rouge">Option</code>. Second, the <code class="language-plaintext highlighter-rouge">Family</code> trait has been removed also in favor of just an associated type on the <code class="language-plaintext highlighter-rouge">Collection</code> trait. Here’s what the new trait looks like an an impl for <code class="language-plaintext highlighter-rouge">Vec</code>:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="n">Collection</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Item</span><span class="p">;</span>
    <span class="k">type</span> <span class="n">Member</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">:</span> <span class="n">Collection</span><span class="o">&lt;</span><span class="n">Item</span> <span class="o">=</span> <span class="n">T</span><span class="o">&gt;</span><span class="p">;</span>
    <span class="k">type</span> <span class="n">Iter</span><span class="o">&lt;</span><span class="nv">'iter</span><span class="o">&gt;</span><span class="p">:</span> <span class="nb">Iterator</span><span class="o">&lt;</span><span class="n">Item</span> <span class="o">=</span> <span class="o">&amp;</span><span class="nv">'iter</span> <span class="k">Self</span><span class="p">::</span><span class="n">Item</span><span class="o">&gt;</span>
    <span class="k">where</span>
        <span class="k">Self</span><span class="p">:</span> <span class="nv">'iter</span><span class="p">;</span>

    <span class="k">fn</span> <span class="nf">empty</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">;</span>
    <span class="k">fn</span> <span class="nf">add</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="k">Self</span><span class="p">::</span><span class="n">Item</span><span class="p">);</span>
    <span class="k">fn</span> <span class="n">iter</span><span class="o">&lt;</span><span class="nv">'iter</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="nv">'iter</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">Iter</span><span class="o">&lt;</span><span class="nv">'iter</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">Collection</span> <span class="k">for</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Item</span> <span class="o">=</span> <span class="n">T</span><span class="p">;</span>
    <span class="k">type</span> <span class="n">Member</span><span class="o">&lt;</span><span class="n">U</span><span class="o">&gt;</span> <span class="o">=</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">U</span><span class="o">&gt;</span><span class="p">;</span>
    <span class="k">type</span> <span class="n">Iter</span><span class="o">&lt;</span><span class="nv">'iter</span><span class="o">&gt;</span> <span class="o">=</span> <span class="nn">std</span><span class="p">::</span><span class="nn">slice</span><span class="p">::</span><span class="n">Iter</span><span class="o">&lt;</span><span class="nv">'iter</span><span class="p">,</span> <span class="n">T</span><span class="o">&gt;</span> <span class="k">where</span> <span class="n">T</span><span class="p">:</span> <span class="nv">'iter</span><span class="p">;</span>

    <span class="k">fn</span> <span class="nf">empty</span><span class="p">()</span> <span class="k">-&gt;</span> <span class="k">Self</span> <span class="p">{</span>
        <span class="nn">Vec</span><span class="p">::</span><span class="nf">new</span><span class="p">()</span>
    <span class="p">}</span>

    <span class="k">fn</span> <span class="nf">add</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">self</span><span class="nf">.push</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="k">fn</span> <span class="n">iter</span><span class="o">&lt;</span><span class="nv">'iter</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;</span><span class="nv">'iter</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">Iter</span><span class="o">&lt;</span><span class="nv">'iter</span><span class="o">&gt;</span> <span class="p">{</span>
        <span class="k">use</span> <span class="nn">std</span><span class="p">::</span><span class="nn">ops</span><span class="p">::</span><span class="n">Deref</span><span class="p">;</span>
        <span class="k">self</span><span class="nf">.deref</span><span class="p">()</span><span class="nf">.iter</span><span class="p">()</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>You could also imagine you might have a function like</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">floatify</span><span class="o">&lt;</span><span class="n">C</span><span class="o">&gt;</span><span class="p">(</span><span class="n">ints</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">C</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nn">C</span><span class="p">::</span><span class="n">Member</span><span class="o">&lt;</span><span class="nb">f32</span><span class="o">&gt;</span>
<span class="k">where</span>
    <span class="n">C</span><span class="p">:</span> <span class="n">Collection</span><span class="o">&lt;</span><span class="n">Item</span><span class="o">=</span><span class="nb">i32</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">res</span> <span class="o">=</span> <span class="nn">C</span><span class="p">::</span><span class="nn">Member</span><span class="p">::</span><span class="o">&lt;</span><span class="nb">f32</span><span class="o">&gt;</span><span class="p">::</span><span class="nf">empty</span><span class="p">();</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">iter</span> <span class="o">=</span> <span class="n">ints</span><span class="nf">.iter</span><span class="p">();</span>
    <span class="k">while</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="o">=</span> <span class="n">iter</span><span class="nf">.next</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">res</span><span class="nf">.add</span><span class="p">(</span><span class="o">*</span><span class="n">v</span> <span class="k">as</span> <span class="nb">f32</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">res</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The second example revolves around mimicking the <code class="language-plaintext highlighter-rouge">Functor</code> typeclass from Haskell and functional programming. In Haskell, a Functor allows you to map the element(s) inside some type of container into something else. In Rust, imagine <code class="language-plaintext highlighter-rouge">Option::map</code> or <code class="language-plaintext highlighter-rouge">Result::map</code>, but generic over many types. There have been a few blog posts published on this topic, so again I’ll just put here a final trait and an impl (this time for <code class="language-plaintext highlighter-rouge">Option</code>):</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="n">Functor</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Inner</span><span class="p">;</span>
    <span class="k">type</span> <span class="n">This</span><span class="o">&lt;</span><span class="n">B</span><span class="o">&gt;</span><span class="p">:</span> <span class="n">Functor</span><span class="p">;</span>

    <span class="k">fn</span> <span class="n">map</span><span class="o">&lt;</span><span class="n">F</span><span class="p">,</span> <span class="n">B</span><span class="o">&gt;</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">f</span><span class="p">:</span> <span class="n">F</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">This</span><span class="o">&lt;</span><span class="n">B</span><span class="o">&gt;</span>
    <span class="k">where</span>
        <span class="n">F</span><span class="p">:</span> <span class="nf">FnOnce</span><span class="p">(</span><span class="k">Self</span><span class="p">::</span><span class="n">Inner</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">B</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">Functor</span> <span class="k">for</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Inner</span> <span class="o">=</span> <span class="n">T</span><span class="p">;</span>
    <span class="k">type</span> <span class="n">This</span><span class="o">&lt;</span><span class="n">B</span><span class="o">&gt;</span> <span class="o">=</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="n">B</span><span class="o">&gt;</span><span class="p">;</span>

    <span class="k">fn</span> <span class="n">map</span><span class="o">&lt;</span><span class="n">F</span><span class="p">,</span> <span class="n">B</span><span class="o">&gt;</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">f</span><span class="p">:</span> <span class="n">F</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">This</span><span class="o">&lt;</span><span class="n">B</span><span class="o">&gt;</span>
    <span class="k">where</span>
        <span class="n">F</span><span class="p">:</span> <span class="nf">FnOnce</span><span class="p">(</span><span class="k">Self</span><span class="p">::</span><span class="n">Inner</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">B</span> <span class="p">{</span>
        <span class="k">self</span><span class="nf">.map</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="similarities-in-the-traits-and-a-problem">Similarities in the traits and a problem</h3>

<p>If you compare these two traits, <code class="language-plaintext highlighter-rouge">Collection</code> and <code class="language-plaintext highlighter-rouge">Functor</code>, you might realize that they look oddly similar. Both have an associated item for the “item inside” (<code class="language-plaintext highlighter-rouge">Item</code> and <code class="language-plaintext highlighter-rouge">Inner</code>) and an associated item that represents the current type, but wrapping a generic item type (<code class="language-plaintext highlighter-rouge">Member&lt;T&gt;</code> and <code class="language-plaintext highlighter-rouge">This&lt;B&gt;</code>).</p>

<p>However, if you think about the way these traits are set up, you might notice a potential problem. There is nothing stopping someone from writing an impl like (assuming <code class="language-plaintext highlighter-rouge">Result: Functor</code> holds):</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">Functor</span> <span class="k">for</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Inner</span> <span class="o">=</span> <span class="n">T</span><span class="p">;</span>
    <span class="k">type</span> <span class="n">This</span><span class="o">&lt;</span><span class="n">B</span><span class="o">&gt;</span> <span class="o">=</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="n">B</span><span class="p">,</span> <span class="p">()</span><span class="o">&gt;</span><span class="p">;</span>

    <span class="k">fn</span> <span class="n">map</span><span class="o">&lt;</span><span class="n">F</span><span class="p">,</span> <span class="n">B</span><span class="o">&gt;</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">f</span><span class="p">:</span> <span class="n">F</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">This</span><span class="o">&lt;</span><span class="n">B</span><span class="o">&gt;</span>
    <span class="k">where</span>
        <span class="n">F</span><span class="p">:</span> <span class="nf">FnOnce</span><span class="p">(</span><span class="k">Self</span><span class="p">::</span><span class="n">Inner</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">B</span> <span class="p">{</span>
        <span class="k">self</span><span class="nf">.map</span><span class="p">(</span><span class="n">f</span><span class="p">)</span><span class="nf">.ok_or</span><span class="p">(())</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Namely, we <em>expect</em> that <code class="language-plaintext highlighter-rouge">This&lt;B&gt;</code> to be equal to <code class="language-plaintext highlighter-rouge">Option&lt;B&gt;</code> (the current container type with a new item type), but instead it is a <code class="language-plaintext highlighter-rouge">Result</code>! Maybe this is okay, but it’s certainly unexpected.</p>

<h3 id="solving-this-with-higher-kinded-types">Solving this with higher-kinded types</h3>

<p>So, how can we solve this? This problem originates mostly because we’re trying to <em>emulate</em> higher-kinded types.</p>

<p>I don’t want to focus on the specific syntax that I’m using (because I’m basically making it up on the spot with little thought and it’s not very relevant), but here’s how you might write <code class="language-plaintext highlighter-rouge">Functor</code> with higher-kinded types:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="n">Functor</span> <span class="k">where</span> <span class="k">Self</span><span class="o">&lt;</span><span class="n">Inner</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="n">map</span><span class="o">&lt;</span><span class="n">F</span><span class="p">,</span> <span class="n">B</span><span class="o">&gt;</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">f</span><span class="p">:</span> <span class="n">F</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="o">&lt;</span><span class="n">B</span><span class="o">&gt;</span>
    <span class="k">where</span>
        <span class="n">F</span><span class="p">:</span> <span class="nf">FnOnce</span><span class="p">(</span><span class="n">Inner</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">B</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">Functor</span> <span class="k">for</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="n">map</span><span class="o">&lt;</span><span class="n">F</span><span class="p">,</span> <span class="n">B</span><span class="o">&gt;</span><span class="p">(</span><span class="k">self</span><span class="p">,</span> <span class="n">f</span><span class="p">:</span> <span class="n">F</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="o">&lt;</span><span class="n">B</span><span class="o">&gt;</span>
    <span class="k">where</span>
        <span class="n">F</span><span class="p">:</span> <span class="nf">FnOnce</span><span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">B</span> <span class="p">{</span>
        <span class="k">self</span><span class="nf">.map</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now, you might be asking how this relates to GATs. And, well, the answer is: <em>it doesn’t</em>, really. The solution I show above is pretty far from the GATs feature itself. But I wanted to cover this for two reasons: 1) The initial examples <em>are</em> likely patterns you will see with GATs, even with the limitation described. 2) In theory, the fundamental compiler features needed to support GATs are likely the fundamentals of the ones needed to be able to “real” higher-kinded types - or maybe something similar but more Rust-like.</p>

<h2 id="a-gatified-iterator">A GATified <code class="language-plaintext highlighter-rouge">Iterator</code></h2>

<p>There are many cases today where people want to do something with <code class="language-plaintext highlighter-rouge">Iterator</code>, <code class="language-plaintext highlighter-rouge">Fn</code>, <code class="language-plaintext highlighter-rouge">Deref</code>, etc. that <em>isn’t yet possible</em>. Instead, what they require is really a GAT version of these traits - often with a lifetime parameter.</p>

<p>The question then becomes: what is the best way to make GAT versions of these traits available? I want to explore here <code class="language-plaintext highlighter-rouge">Iterator</code>, since that is arguably the most well-known example case. I want to look first at the pattern that requires GATs. Then, I want to introduce a <code class="language-plaintext highlighter-rouge">LendingIterator</code>, and explain why might be a less-than-ideal solution. I’ll show a bit about a couple of the things that it might take to replace <code class="language-plaintext highlighter-rouge">Iterator</code> with a GATified version (in a backwards-compatible manner). And I’ll end off the section with a somewhat crazy thought I was actually able to get working as I was writing this blog post.</p>

<h3 id="an-example-case-on-returning-an-item-that-borrows-from-self">An example case on returning an item that borrows from <code class="language-plaintext highlighter-rouge">Self</code></h3>

<p>Let’s start by looking at what the current <code class="language-plaintext highlighter-rouge">Iterator</code> trait looks like:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="nb">Iterator</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Item</span><span class="p">;</span>
    <span class="k">fn</span> <span class="nf">next</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">Item</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Pretty simple, but I’ve obviously left out a large chunk of methods with default implementations, like <code class="language-plaintext highlighter-rouge">for_each</code>, <code class="language-plaintext highlighter-rouge">map</code>, or <code class="language-plaintext highlighter-rouge">peekable</code>. I’ve left them out for simplicity, but they are important and I’ll talk about that in a bit.</p>

<p>To introduce the pattern that requires GATs, I’ll use the <code class="language-plaintext highlighter-rouge">std::io::BufRead</code> trait. This is implemented most clearly by the <code class="language-plaintext highlighter-rouge">std::io::BufReader</code> struct. In short, this trait represents a type that implements <code class="language-plaintext highlighter-rouge">std::io::Read</code> but <em>also</em> keeps an internal buffer, allowing it to be able to do extra things, like returning line by line.</p>

<p>I want to focus on a single method on <code class="language-plaintext highlighter-rouge">BufRead</code>:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">trait</span> <span class="n">BufRead</span><span class="p">:</span> <span class="n">Read</span> <span class="p">{</span>
    <span class="k">fn</span> <span class="nf">lines</span><span class="p">(</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">Lines</span><span class="o">&lt;</span><span class="k">Self</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This function returns a struct <code class="language-plaintext highlighter-rouge">Lines</code> which implements <code class="language-plaintext highlighter-rouge">Iterator</code> with an <code class="language-plaintext highlighter-rouge">Item</code> of <code class="language-plaintext highlighter-rouge">Result&lt;String&gt;</code>. Let’s imagine it gets used like:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">r</span><span class="p">:</span> <span class="n">BufReader</span><span class="o">&lt;</span><span class="n">_</span><span class="o">&gt;</span> <span class="o">=</span> <span class="o">...</span><span class="p">;</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">lines</span> <span class="o">=</span> <span class="n">r</span><span class="nf">.lines</span><span class="p">();</span>
    <span class="k">while</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="n">line</span><span class="p">)</span> <span class="o">=</span> <span class="n">lines</span><span class="nf">.next</span><span class="p">()</span> <span class="p">{</span>
        <span class="nd">println!</span><span class="p">(</span><span class="s">"{line}"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now what’s <em>wrong</em> with this (aside from me being able to use a for loop - I’ll get there). It might seem like a philosophical question, but there really is something suboptimal: even though we only look at one line at a time, we allocate a new <code class="language-plaintext highlighter-rouge">String</code> for each one. Of course, this is the exact reason we need GATs. If we wanted to be able to reuse the same memory between calls to <code class="language-plaintext highlighter-rouge">next</code>, then we would have to ensure that nobody else hold a reference to that memory. But  with the current definition of <code class="language-plaintext highlighter-rouge">Iterator::next</code>, <em>the return time can outlive the call</em>.</p>

<h3 id="introducing-lendingiterator">Introducing <code class="language-plaintext highlighter-rouge">LendingIterator</code></h3>

<p>Let’s introduce a <code class="language-plaintext highlighter-rouge">Iterator</code>-like trait that could handle this correctly:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="n">LendingIterator</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Item</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="k">where</span> <span class="k">Self</span><span class="p">:</span> <span class="nv">'a</span><span class="p">;</span>
    <span class="k">fn</span> <span class="nf">next</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">Item</span><span class="o">&lt;</span><span class="nv">'_</span><span class="o">&gt;</span><span class="p">;</span> 
<span class="p">}</span>
</code></pre></div></div>

<p>Here, I’ve defined a new trait, <code class="language-plaintext highlighter-rouge">LendingIterator</code>, that mirrors <code class="language-plaintext highlighter-rouge">Iterator</code>, except for a new lifetime <code class="language-plaintext highlighter-rouge">'a</code> on <code class="language-plaintext highlighter-rouge">Item</code>. It does exactly what we want:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">Lines</span><span class="o">&lt;</span><span class="n">B</span><span class="p">:</span> <span class="n">BufRead</span><span class="o">&gt;</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span> <span class="c1">// Stores the state needed to read lines</span>

<span class="k">impl</span><span class="o">&lt;</span><span class="n">B</span><span class="p">:</span> <span class="n">BufRead</span><span class="o">&gt;</span> <span class="n">LendingIterator</span> <span class="k">for</span> <span class="n">Lines</span><span class="o">&lt;</span><span class="n">B</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Item</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="o">=</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="nb">str</span><span class="p">;</span>

    <span class="c1">// The lifetime of the return type is tied to the lifetime of the call</span>
    <span class="k">fn</span> <span class="nf">next</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="k">Self</span><span class="p">::</span><span class="n">Item</span><span class="o">&lt;</span><span class="nv">'_</span><span class="o">&gt;</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="n">read_two_lines</span><span class="o">&lt;</span><span class="n">B</span><span class="p">:</span> <span class="n">BufRead</span><span class="o">&gt;</span><span class="p">(</span><span class="k">mut</span> <span class="n">lines</span><span class="p">:</span> <span class="n">Lines</span><span class="o">&lt;</span><span class="n">B</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">while</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="n">line</span><span class="p">)</span> <span class="o">=</span> <span class="n">lines</span><span class="nf">.next</span><span class="p">()</span> <span class="p">{</span>
        <span class="c1">// `line` is only a `&amp;str`</span>
        <span class="c1">// The reference is dropped before the next call</span>
        <span class="nd">println!</span><span class="p">(</span><span class="s">"{line}"</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="c1">// We also store two lines at a time:</span>
    <span class="k">let</span> <span class="n">line1</span> <span class="o">=</span> <span class="n">lines</span><span class="nf">.next</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">line2</span> <span class="o">=</span> <span class="n">lines</span><span class="nf">.next</span><span class="p">();</span> <span class="c1">// &lt;- Error: the lifetime from `line1` is still active</span>
    <span class="nd">println!</span><span class="p">(</span><span class="s">"{line1} {line2}"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>So, this looks great. Why is this imperfect? Well, remember all those methods on iterator with default implementations? We now need to rewrite those. Also, any APIs that take <code class="language-plaintext highlighter-rouge">Iterator</code> but don’t read more than one <code class="language-plaintext highlighter-rouge">Item</code> at a time would need to be to changed or duplicated to take <code class="language-plaintext highlighter-rouge">LendingIterator</code>.</p>

<h3 id="reusing-iterator-in-a-lendingiterator-way">Reusing <code class="language-plaintext highlighter-rouge">Iterator</code> in a <code class="language-plaintext highlighter-rouge">LendingIterator</code> way</h3>

<p>So, maybe we don’t want a completely separate <code class="language-plaintext highlighter-rouge">LendingIterator</code> trait from <code class="language-plaintext highlighter-rouge">Iterator</code>. What can we do instead? Well, what if we <em>just</em> added a <code class="language-plaintext highlighter-rouge">'a</code> parameter to <code class="language-plaintext highlighter-rouge">Iterator::Item</code>. Let’s go through some of the different problems that would have to be worked through.</p>

<p>To start, I want to actually just introduce some code, which will help me explain things after.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">from_iter</span><span class="o">&lt;</span><span class="n">A</span><span class="p">,</span> <span class="n">I</span><span class="o">&gt;</span><span class="p">(</span><span class="k">mut</span> <span class="n">iter</span><span class="p">:</span> <span class="n">I</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">A</span><span class="o">&gt;</span>
<span class="k">where</span>
    <span class="n">I</span><span class="p">:</span> <span class="nb">Iterator</span><span class="o">&lt;</span><span class="n">Item</span> <span class="o">=</span> <span class="n">A</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">v</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nn">I</span><span class="p">::</span><span class="n">Item</span><span class="o">&gt;</span> <span class="o">=</span> <span class="nd">vec!</span><span class="p">[];</span>
    <span class="k">while</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="n">item</span><span class="p">)</span> <span class="o">=</span> <span class="n">iter</span><span class="nf">.next</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">v</span><span class="nf">.push</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">v</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This is completely fine. In fact, it’s mostly the same as the <code class="language-plaintext highlighter-rouge">FromIterator</code> implementation for <code class="language-plaintext highlighter-rouge">Vec</code>.</p>

<p>Let me also show what this would look like with a <code class="language-plaintext highlighter-rouge">LendingIterator</code>. Keep in mind that we <em>want</em> this to be just <code class="language-plaintext highlighter-rouge">Iterator</code> with a lifetime parameter on <code class="language-plaintext highlighter-rouge">Iterator::Item</code>. I’m keeping them separate here to keep comparisons easy to understand.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">from_iter</span><span class="o">&lt;</span><span class="n">A</span><span class="p">,</span> <span class="n">I</span><span class="o">&gt;</span><span class="p">(</span><span class="k">mut</span> <span class="n">iter</span><span class="p">:</span> <span class="n">I</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">A</span><span class="o">&gt;</span>
<span class="k">where</span>
    <span class="n">I</span><span class="p">:</span> <span class="k">for</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="n">LendingIterator</span><span class="o">&lt;</span><span class="n">Item</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="o">=</span> <span class="n">A</span><span class="o">&gt;</span><span class="p">,</span> <span class="c1">// (1)</span>
<span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">v</span><span class="cm">/*: Vec&lt;I::Item&gt;*/</span> <span class="o">=</span> <span class="nd">vec!</span><span class="p">[];</span> <span class="c1">// (2)</span>
    <span class="k">while</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="n">item</span><span class="p">)</span> <span class="o">=</span> <span class="n">iter</span><span class="nf">.next</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">v</span><span class="nf">.push</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">v</span>
<span class="p">}</span>
</code></pre></div></div>

<p>This also works, but differs from the <code class="language-plaintext highlighter-rouge">Iterator</code> case in two places, which I’ll talk about next.</p>

<p>Note: It’s nice to see that borrow checker knows that the item being iterated over doesn’t capture the <code class="language-plaintext highlighter-rouge">self</code> lifetime from <code class="language-plaintext highlighter-rouge">next</code>; with this, we can store <code class="language-plaintext highlighter-rouge">item</code> in the Vec without problems. This makes intuitive sense and it’s good to see that <em>this</em> isn’t a problem we have to work through.</p>

<h4 id="i-fora-lendingiteratoritema--a"><code class="language-plaintext highlighter-rouge">I: for&lt;'a&gt; LendingIterator&lt;Item&lt;'a&gt; = A&gt;</code></h4>

<p>Let’s first look at the line labeled <code class="language-plaintext highlighter-rouge">(1)</code> above. What is this <code class="language-plaintext highlighter-rouge">for&lt;'a&gt;</code> business? Well, we have to have <em>some</em> way to denote the where clause “the item being iterated over is <code class="language-plaintext highlighter-rouge">A</code>, regardless of the lifetime passed.” In other words, the type being iterated over can’t name the lifetime passed. Therefore, it acts exactly like a non-generic associated type.</p>

<p>Now, let’s remember that we want to replace the definition of <code class="language-plaintext highlighter-rouge">Iterator</code> with the definition of <code class="language-plaintext highlighter-rouge">LendingIterator</code>. So, we need to make <code class="language-plaintext highlighter-rouge">I: Iterator&lt;Item = A&gt;</code> “desugar” into <code class="language-plaintext highlighter-rouge">I: for&lt;'a&gt; Iterator&lt;Item&lt;'a&gt; = A&gt;</code>. Semantically, this is actually fairly straightforward.</p>

<h4 id="iteratoritem"><code class="language-plaintext highlighter-rouge">Iterator::Item</code></h4>

<p>Now let’s look at the line labeled <code class="language-plaintext highlighter-rouge">(2)</code>.</p>

<p>In the <code class="language-plaintext highlighter-rouge">Iterator</code> example, we can name the type of the item being iterated by doing <code class="language-plaintext highlighter-rouge">I::Item</code>. With <code class="language-plaintext highlighter-rouge">LendingIterator</code> though, we can’t do this, because <code class="language-plaintext highlighter-rouge">I::Item</code> isn’t a type, it’s a <em>type constructor</em>. To get an actual type, we have to use a lifetime, like <code class="language-plaintext highlighter-rouge">I::Item&lt;'static&gt;</code>. This analogous in that you can’t just write <code class="language-plaintext highlighter-rouge">let x: Vec;</code>, you have to write something like <code class="language-plaintext highlighter-rouge">let x: Vec&lt;()&gt;;</code>.</p>

<p>Now, you might say “oh, but you could just write <code class="language-plaintext highlighter-rouge">Vec&lt;A&gt;</code> or <code class="language-plaintext highlighter-rouge">Vec&lt;I::Item&lt;'static&gt;&gt;</code> and it will be the same” and you would be correct: That would be fine. But if only it was so simple.</p>

<p>Again, let’s remember the goal of converting <code class="language-plaintext highlighter-rouge">Iterator</code>. We can’t suddently just break all the code out there. So, we have to figure out how to make <code class="language-plaintext highlighter-rouge">v: Vec&lt;I::Item&gt;</code> work, even if <code class="language-plaintext highlighter-rouge">Iterator::Item</code> has a lifetime parameter. For the example above, we could just handwave and see that we know that it doesn’t matter what lifetime we pass to <code class="language-plaintext highlighter-rouge">I::Item</code>, since <code class="language-plaintext highlighter-rouge">A</code> can’t bind it. So, we could “desugar” this to either <code class="language-plaintext highlighter-rouge">I::Item&lt;'static&gt;</code>, some higher-ranked <code class="language-plaintext highlighter-rouge">for&lt;'a&gt; I::Item&lt;'a&gt;</code>, or maybe some “empty” lifetime <code class="language-plaintext highlighter-rouge">I::Item&lt;'empty&gt;</code>.</p>

<h4 id="complicating-matters-a-bit">Complicating matters a bit</h4>

<p>Let’s look at this example:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">from_iter</span><span class="o">&lt;</span><span class="n">I</span><span class="o">&gt;</span><span class="p">(</span><span class="k">mut</span> <span class="n">iter</span><span class="p">:</span> <span class="n">I</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nn">I</span><span class="p">::</span><span class="n">Item</span><span class="o">&gt;</span>
<span class="k">where</span>
    <span class="n">I</span><span class="p">:</span> <span class="n">LendingIterator</span><span class="p">,</span>
<span class="p">{</span>
    <span class="o">...</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Well, this is more complicated. The code as written doesn’t make much sense. Of course, if this were just a “clean” <code class="language-plaintext highlighter-rouge">LendingIterator</code> trait, then we just maybe want to return <code class="language-plaintext highlighter-rouge">Vec&lt;I::Item&lt;'static&gt;&gt;</code> and all is well and good (we have to pass <em>some</em> lifetime to the GAT). But, if we imagine that we just took <code class="language-plaintext highlighter-rouge">Iterator</code> and added a lifetime parameter, it becomes clear that we need some sort of <em>implicit</em> <code class="language-plaintext highlighter-rouge">I: for&lt;'a&gt; Iterator&lt;Item&lt;'a&gt; = A&gt;</code> for <code class="language-plaintext highlighter-rouge">Iterator</code>.</p>

<p>But now if <code class="language-plaintext highlighter-rouge">Iterator::Item</code> implicitly <em>can’t</em> capture a lifetime, we have to allow code to <em>opt-in</em> to that. What might the syntax for that look like? To be honest, I’m not really sure. To extend upon this, you likely don’t want <em>all</em> code using traits with GATs to have to opt-in to being able to allow the GATs to name a lifetime. So, <code class="language-plaintext highlighter-rouge">Iterator</code> would probably be special in some way.</p>

<p>I would love to hear thoughts on how <em>you</em> would like to interact with a GATified <code class="language-plaintext highlighter-rouge">Iterator</code>.</p>

<h4 id="can-they-be-separate-traits"><em>Can</em> they be separate traits?</h4>

<p>As I was writing this blog post, I played around with an idea that was brought up at one point or another. I couldn’t get it to work then, but was able to get <em>something</em> to work, at least a little bit this time.</p>

<p>So, I’m going to spitball this potentially crazy idea, if for no other reason than to let people go “what the heck is he thinking” and pick it apart.</p>

<p>So bear with me here. What if we <em>do</em> have two traits, <code class="language-plaintext highlighter-rouge">Iterator</code> and <code class="language-plaintext highlighter-rouge">LendingIterator</code>, but they look something like this:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">trait</span> <span class="n">LendingIterator</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Item</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="k">where</span> <span class="k">Self</span><span class="p">:</span> <span class="nv">'a</span><span class="p">;</span>

    <span class="k">fn</span> <span class="nf">next</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="k">Self</span><span class="p">::</span><span class="n">Item</span><span class="o">&lt;</span><span class="nv">'_</span><span class="o">&gt;&gt;</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">pub</span> <span class="k">trait</span> <span class="nb">Iterator</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Item</span><span class="p">;</span>

    <span class="k">fn</span> <span class="nf">next</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="k">Self</span><span class="p">::</span><span class="n">Item</span><span class="o">&gt;</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">impl</span><span class="o">&lt;</span><span class="nv">'i</span><span class="p">,</span> <span class="n">I</span><span class="p">:</span> <span class="nb">Iterator</span> <span class="o">+</span> <span class="nv">'i</span><span class="o">&gt;</span> <span class="n">LendingIterator</span> <span class="k">for</span> <span class="n">I</span> <span class="p">{</span>
    <span class="k">type</span> <span class="n">Item</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="o">=</span> <span class="nn">I</span><span class="p">::</span><span class="n">Item</span> <span class="k">where</span> <span class="n">I</span><span class="p">:</span> <span class="nv">'a</span><span class="p">;</span>

    <span class="k">fn</span> <span class="nf">next</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="k">Self</span><span class="p">::</span><span class="n">Item</span><span class="o">&lt;</span><span class="nv">'i</span><span class="o">&gt;&gt;</span> <span class="p">{</span>
        <span class="nn">Iterator</span><span class="p">::</span><span class="nf">next</span><span class="p">(</span><span class="k">self</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>In words, every implementation of <code class="language-plaintext highlighter-rouge">Iterator</code> automatically implements <code class="language-plaintext highlighter-rouge">LendingIterator</code> with the items equal.</p>

<p>I <em>think</em> this <em>mostly</em> works.</p>

<p>Here are couple examples of how you might use these:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">print_items</span><span class="o">&lt;</span><span class="n">I</span><span class="o">&gt;</span><span class="p">(</span><span class="k">mut</span> <span class="n">iter</span><span class="p">:</span> <span class="n">I</span><span class="p">)</span>
<span class="k">where</span>
    <span class="n">I</span><span class="p">:</span> <span class="n">LendingIterator</span><span class="p">,</span>
    <span class="k">for</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="nn">I</span><span class="p">::</span><span class="n">Item</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">:</span> <span class="nn">std</span><span class="p">::</span><span class="nn">fmt</span><span class="p">::</span><span class="n">Debug</span><span class="p">,</span>
<span class="p">{</span>
    <span class="k">while</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="n">item</span><span class="p">)</span> <span class="o">=</span> <span class="n">iter</span><span class="nf">.next</span><span class="p">()</span> <span class="p">{</span>
        <span class="nd">println!</span><span class="p">(</span><span class="s">"{item:?}"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="n">collect_items</span><span class="o">&lt;</span><span class="n">I</span><span class="o">&gt;</span><span class="p">(</span><span class="k">mut</span> <span class="n">iter</span><span class="p">:</span> <span class="n">I</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nn">I</span><span class="p">::</span><span class="n">Item</span><span class="o">&gt;</span>
<span class="k">where</span>
    <span class="n">I</span><span class="p">:</span> <span class="nb">Iterator</span><span class="p">,</span>
<span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">v</span> <span class="o">=</span> <span class="nd">vec!</span><span class="p">[];</span>
    <span class="k">while</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="n">item</span><span class="p">)</span> <span class="o">=</span> <span class="n">iter</span><span class="nf">.next</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">v</span><span class="nf">.push</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">v</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Importantly, you could change the top function to use <code class="language-plaintext highlighter-rouge">Iterator</code> and it works (though it accepts <em>fewer</em> types, since we accepted all <code class="language-plaintext highlighter-rouge">Iterator</code> types already because of the blanket impl). You <em>cannot</em> change the bottom function to use <code class="language-plaintext highlighter-rouge">LendingIterator</code>, since that would end up with overlapping mutable borrows.</p>

<p>There are couple pain points here that I’ve found as I played with it a bit; let me go through them.</p>

<p>First, you can’t actually call <code class="language-plaintext highlighter-rouge">next()</code> on a type that implements <code class="language-plaintext highlighter-rouge">Iterator</code> without disambiguating the <code class="language-plaintext highlighter-rouge">next</code> function of <code class="language-plaintext highlighter-rouge">Iterator</code> and <code class="language-plaintext highlighter-rouge">LendingIterator</code>. The “simple” solution is to rename <code class="language-plaintext highlighter-rouge">LendingIterator::next</code> to something like <code class="language-plaintext highlighter-rouge">lend_next</code>. I’ve tried making the defintion of <code class="language-plaintext highlighter-rouge">Iterator</code> be <code class="language-plaintext highlighter-rouge">Iterator: LendingIterator</code>, but haven’t gotten it to work.</p>

<p>The other pain point (which might actually be <em>good</em>), is that all (already existing) functions don’t <em>automatically</em> get to take a <code class="language-plaintext highlighter-rouge">LendingIterator</code>. I <em>think</em> changing from <code class="language-plaintext highlighter-rouge">I: Iterator</code> to <code class="language-plaintext highlighter-rouge">I: LendingIterator</code> is a backwards compatible change, but haven’t worked through it to be sure. Related to this, if your impl of <code class="language-plaintext highlighter-rouge">LendingIterator</code> <em>just so happens</em> to not name the lifetime parameter on <code class="language-plaintext highlighter-rouge">Item</code>, you can’t use a function that takes <code class="language-plaintext highlighter-rouge">Iterator</code>. But again, maybe this is the right thing.</p>

<p>And, of course, this doesn’t generalize to other traits with GATs.</p>

<p>So, yeah. This was my crazy revelation while writing this. Here’s a playground link where I’ve added some other examples, if you’re interested in picking it apart: https://play.rust-lang.org/?version=nightly&amp;mode=debug&amp;edition=2021&amp;gist=7647fd487f1733fe97fa55c38e4071ab</p>

<h2 id="the-fora-self-a-problem">The <code class="language-plaintext highlighter-rouge">for&lt;'a&gt; Self: 'a</code> problem</h2>

<p>It’s interesting, just earlier this week an absolutely beautiful blog post was published by Sabrina Jewson (<a href="https://sabrinajewson.org/blog/the-better-alternative-to-lifetime-gats">link</a>) that mostly covered this problem, and gave some good and interesting solutions.</p>

<p>I’ll briefly restate the problem, but if you’re interested in a more “user-friendly” explantation defintion go check out Sabrina’s post; it’s great. I’ll use the same <code class="language-plaintext highlighter-rouge">LendingIterator</code> example Sabrina uses, the problem definitely pops up in <a href="https://github.com/rust-lang/rust/issues/90696">even</a> <a href="https://github.com/rust-lang/rust/issues/91693">more</a> <a href="https://github.com/rust-lang/rust/issues/92096">subtle</a> <a href="https://github.com/rust-lang/rust/issues/95268">places</a>.</p>

<p>So, the problem in the <code class="language-plaintext highlighter-rouge">LendingIterator</code> comes from the interaction of two pieces of code.</p>

<p>First, there is the <code class="language-plaintext highlighter-rouge">Self: 'this</code> bound on the <code class="language-plaintext highlighter-rouge">Item</code> associated type:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">trait</span> <span class="n">LendingIterator</span> <span class="p">{</span>
	<span class="k">type</span> <span class="n">Item</span><span class="o">&lt;</span><span class="nv">'this</span><span class="o">&gt;</span> <span class="k">where</span> <span class="k">Self</span><span class="p">:</span> <span class="nv">'this</span><span class="p">;</span>
                        <span class="c1">// ^^^^^^^^^^^ this one</span>
    <span class="o">...</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Second, we encounter a piece of code where we reference an GAT using a lifetime from a HRTB:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">print_items</span><span class="o">&lt;</span><span class="n">I</span><span class="o">&gt;</span><span class="p">(</span><span class="k">mut</span> <span class="n">iter</span><span class="p">:</span> <span class="n">I</span><span class="p">)</span>
<span class="k">where</span>
	<span class="n">I</span><span class="p">:</span> <span class="n">LendingIterator</span><span class="p">,</span>
	<span class="k">for</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="nn">I</span><span class="p">::</span><span class="n">Item</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span><span class="p">:</span> <span class="n">Debug</span><span class="p">,</span> <span class="c1">// here</span>
<span class="p">{</span>
	<span class="k">while</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="n">item</span><span class="p">)</span> <span class="o">=</span> <span class="n">iter</span><span class="nf">.next</span><span class="p">()</span> <span class="p">{</span>
		<span class="nd">println!</span><span class="p">(</span><span class="s">"{item:?}"</span><span class="p">);</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>As noted in Sabrina’s post, the problem comes because we try to prove that <code class="language-plaintext highlighter-rouge">for&lt;'a&gt; I: 'a</code>, meaning that we require for any lifetime that we pick, <code class="language-plaintext highlighter-rouge">I</code> must outlive it. This isn’t really right, because ultimately, we don’t need to prove that I can outlive <em>any</em> lifetime in this context. We only need to prove that <code class="language-plaintext highlighter-rouge">I</code> outlives any lifetime that we <em>could</em> have provided <em>if the GAT was valid</em> (in this case, this is only true if <code class="language-plaintext highlighter-rouge">I: 'a</code>, which makes <code class="language-plaintext highlighter-rouge">for&lt;'a&gt; I: 'a</code> trivially provable).</p>

<p>This is a bug. And one that is fixable in an almost certainly backwards-compatible manner. But it’s also tough to fix. So it’s not something we want to block stabilization on.</p>

<p>To give a <em>brief</em> teaser to what a fix <em>might</em> look like, you might want to check out Niko Matsakis <a href="https://github.com/nikomatsakis/a-mir-formality">a-mir-formality</a>. The key part of this formalism of the Rust type system (that differs from the current rustc and Chalk solvers), is the introduction of the “ensures” clause and the separation from an “implication” clause. If I understand the model correctly, I think this is crucial to being able to model and solve this problem.</p>

<h2 id="object-safety">Object safety</h2>

<p>Right now, you can’t use GATs with <code class="language-plaintext highlighter-rouge">dyn</code>. In other words, the following doesn’t work:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">print_items</span><span class="p">(</span><span class="n">items</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="k">dyn</span> <span class="k">for</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="n">LendingIterator</span><span class="o">&lt;</span><span class="n">Item</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="o">=</span> <span class="o">&amp;</span><span class="nv">'a</span> <span class="nb">str</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="n">item</span> <span class="k">in</span> <span class="n">items</span> <span class="p">{</span>
        <span class="nd">println!</span><span class="p">(</span><span class="s">"{item}"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We expect this to work just fine one day, but there are still some implementation design work to be done.</p>

<h2 id="wrapping-up">Wrapping up</h2>

<p>Hopefully this post provides a little bit of a glimmer of a shiny future with GATs. I wanted to make this post more “glamorous” but really just fell short on time. I might publish a part 2 of this at some point in the coming months; we’ll see.</p>

<p>Ultimately though, I don’t think I can do justice to the many different use cases of GATs and the power they provide. If you’d like to get a sense of the many projects that are “waiting” for GATs, just take a scroll through the <a href="https://github.com/rust-lang/rust/issues/44265">tracking issue</a> and see the numerous issues from external projects linking to it. I can’t wait to see the types of projects people build with them.</p>

<p>If you feel like I’ve missed anything, please feel to reach out.</p>]]></content><author><name></name></author><category term="rust" /><summary type="html"><![CDATA[This was a surprisingly difficult blog post to write. Between general life things getting in the way and feeling a bit of lost steam, this took much longer than I expected.]]></summary></entry><entry><title type="html">A thanks to the traits working group in 2021</title><link href="https://jackhuey.me/rust/2022/03/25/a-thanks.html" rel="alternate" type="text/html" title="A thanks to the traits working group in 2021" /><published>2022-03-25T03:00:00+00:00</published><updated>2022-03-25T03:00:00+00:00</updated><id>https://jackhuey.me/rust/2022/03/25/a-thanks</id><content type="html" xml:base="https://jackhuey.me/rust/2022/03/25/a-thanks.html"><![CDATA[<p>So…this is awkward. I wanted to write this post near the end of 2021 or beginning of 2022, but time got away from me, as it does so often. However, a half-completed draft has been open in my browser this entire time, and I think it’d be a shame for it to go to waste and <em>not</em> celebrate all the work done on traits working-group related things and to celebrate the people who have done that amazing work. Given that this is “unofficial” though, I’ll be a little less formal than I otherwise would if this was posted to the <a href="https://blog.rust-lang.org/inside-rust/">Inside Rust Blog</a>.</p>

<p>So, first, if you aren’t familiar with the traits working group, the tl;dr is that it’s traditonally been dedicated maintaining and improving rustc’s trait system design and implementation (including writing a new trait solver, <a href="https://github.com/rust-lang/chalk">Chalk</a>). In recent times, the scope has, in practice, broadened a bit to include the typesystem overall. Stayed tuned for fun things about this soon.</p>

<p>The last real “public” post from the traits working group was at the end of our last sprint…in <a href="https://blog.rust-lang.org/inside-rust/2020/07/17/traits-sprint-3.html">July 17 of 2020</a>. We certainly have been busy since then though. This post will mainly focus on the work done in 2021, but I will do my best to call out notable points from the latter half of 2020.</p>

<p>There will be roughly two kinds of work highlighted here: that which falls under a lang team <a href="https://lang-team.rust-lang.org/initiatives.html">initiative</a> and that which doesn’t, but aligns with longer-term goals of the traits working group. I originally wanted this post to be a larger overview of the different projects and work, but in the interest of just “getting this out”, I’ll likely keep things fairly brief in explanations. If you’re interested in any of the work you see here, I urge you to either look through the cited pull requests or issues, to browse the initiatve repositories, or to come join us on <a href="https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits">Zulip</a> and have a chat.</p>

<p>If you find something I’ve missed here, or any other mistake, please feel free to message me on Zulip; I really don’t want someone to feel like I’ve left them out intentially and I want them to get the credit they deserve. With that being said, let’s get started.</p>

<p>(The issue numbers referenced in this post refer to issues on the <a href="https://github.com/rust-lang/rust">rustc repository</a>).</p>

<h2 id="initiatives">Initiatives</h2>

<p>For each of these initiatives, I’ll give a brief snippet as to what the initiative is for, as well as list the people who have contributed (also listing pull requests made and issues fixed) to each. Importantly, there are certainly going to be people that I miss here, either because they haven’t <em>directly</em> contributed code (but have been involved in discussion or design) or because they help out tangentially (making PR rollups, adding regression tests, etc.). I do want to specifically thank them now; that work is important too.</p>

<p>I also want to specifically call out one particular person who will be underrepresented below, but deserves recognition: <a href="https://github.com/nikomatsakis">Niko Matsakis</a>. Though he hasn’t made many pull requests for these, he serves as the lang team liason for basically all of them and is instrumental in design and implementation discussions for this work. He also does amazing work co-leading the traits working group with me.</p>

<h3 id="generic-associated-types-gats">Generic associated types (GATs)</h3>

<p><a href="https://rust-lang.github.io/generic-associated-types-initiative/">Link to initiative</a></p>

<p>For a nice introduction to what GATs are, I’ll refer you to a <a href="https://blog.rust-lang.org/2021/08/03/GATs-stabilization-push.html">blog post</a> I wrote last August. However, in a few words: it’s a really neat and powerful language feature that is nearing stabilization. Essentially, it allows you to have generics on associated types in traits (surpisingly given the name). Since the blog post in August, there have been many bug and diagnostic fixes made. We missed the “next couple months” hope for stabilization from the blog post, but that’s okay. While I won’t cover all the work done <em>this year</em> (which is siginficant too), you’ll see that 2021 was a busy year in terms of GAT work. We expecting to likely stabilize next release cycle (well, that nightly).</p>

<h4 id="contributions">Contributions</h4>

<p><a href="https://github.com/b-naber">b-naber</a>
PRs: #79554, #82272, #90801 Issues: #67510, #68648 #68649, #68650, #68652, #74684, #76535, #79422, #80433, #81801, #81961, #81862, #84439, #90612</p>

<p><a href="https://github.com/lcnr">lcnr</a>
PRs: #80558 Issues: #69184, #80766</p>

<p><a href="https://github.com/BoxyUwU">BoxyUwU</a>
PRs: #81911 Issues: #75415, #79666</p>

<p><a href="https://github.com/jackh726">Jack Huey (jackh726)</a>
PRs: #86993, #87244, #87281, #84622, #87478, #85499, #89914, #87900, #88846, #88441, #89823, #91849, #89970, #88336, #87478, #84623, #90076, #90887, #91853, #92118, #92191 Issues: #76407, #76826, #78113, #81487, #81823, #84931, #85921, #86787, #87429, #87762, #88360, #88459, #89639, #91036, #90888, #91348</p>

<p><a href="https://github.com/SkiFire13">Giacomo Stevanato (SkiFire13)</a>
PRs: #85375 Issues: #85347</p>

<p><a href="https://github.com/JohnTitor">Yuki Okushi (JohnTitor)</a>
PRs: #86505 Issues: #86483</p>

<p><a href="https://github.com/oli-obk">Oli Scherer (oli-obk)</a>
PRs: #89229 Issues: #87258, #88595</p>

<p><a href="https://github.com/audunhalland">Audun Halland (audunhalland)</a>
PRs: #89341 Issues: #89188</p>

<p>Unattributed
#79949, #79636, #78671, #70303, #70304, #71176, #81712, #79768, #87750, #88287, #88405, #90014</p>

<h3 id="impl-traits-taits">Impl traits (TAITs)</h3>

<p><a href="https://rust-lang.github.io/impl-trait-initiative/">Link to initiative</a></p>

<p>This feature essentially allows you to do something like</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="n">AwesomeTrait</span> <span class="p">{}</span>

<span class="k">type</span> <span class="n">MyType</span> <span class="o">=</span> <span class="k">impl</span> <span class="n">AwesomeTrait</span><span class="p">;</span>
</code></pre></div></div>

<p>Basically, rather than requiring you to specify the exact type for <code class="language-plaintext highlighter-rouge">MyType</code>, it can be <em>inferred</em> from how it’s used <em>in the module it’s defined</em>. This means to users of e.g. a library it’s “opaque” - all you know is that it impls <code class="language-plaintext highlighter-rouge">AwesomeTrait</code>. This is also especially nice when the type <em>can’t be named</em>, like for closures.</p>

<h4 id="contributions-1">Contributions</h4>

<p><a href="https://github.com/spastorino">Santiago Pastorino (spastorino)</a>
PRs: #86118, #87141, #87501
Issues: #73481, #77179, #85113</p>

<p><a href="https://github.com/oli-obk">Oli Scherer (oli-obk)</a>
PRs: #87287 #89229, #87107, #87200, #87287, #82898, #87587, #89045, #89024, #90376
Issues: #74280, #88595</p>

<p><a href="https://github.com/b-naber">b-naber</a>
PRs: #85755
Issues: #83190, #78450</p>

<p><a href="https://github.com/tmiasko">tmiasko</a>
PRs: #81008
Issues: #80998</p>

<p><a href="https://github.com/estebank">Esteban Kuber (estebank)</a>
PRs: #83954
Issues: #83613</p>

<p><a href="https://github.com/nikomatsakis">Niko Matsakis (nikomatsakis)</a>
PRs: #84701 #86437</p>

<p>Unattributed
#63355, #63591, #65384, #69323, #86201, #88287, #90014</p>

<h3 id="dyn-upcasting">Dyn upcasting</h3>

<p><a href="https://rust-lang.github.io/dyn-upcasting-coercion-initiative/design-discussions/">Link to initiative</a></p>

<p>Have you ever tried to do something like only to have rustc yell at you?</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">trait</span> <span class="n">Foo</span> <span class="p">{}</span>
<span class="k">trait</span> <span class="n">Bar</span><span class="p">:</span> <span class="n">Foo</span> <span class="p">{}</span>

<span class="k">let</span> <span class="n">bar_type</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">dyn</span> <span class="n">Bar</span> <span class="o">=</span> <span class="o">...</span><span class="p">;</span>
<span class="k">let</span> <span class="n">foo_type</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">dyn</span> <span class="n">Foo</span> <span class="o">=</span> <span class="n">bar_type</span><span class="p">;</span>
</code></pre></div></div>

<p>Well, with this feature, the above code just works.</p>

<h4 id="contributions-2">Contributions</h4>

<p><a href="https://github.com/crlf0710">Charles Lew (crlf0710)</a>
PRs: #86264, #86291, #86461, #86475, #88135, #90536 Issues: #89190, #86324, #90177</p>

<h3 id="negative-impls">Negative impls</h3>

<p><a href="https://rust-lang.github.io/negative-impls-initiative/">Link to initiative</a></p>

<p>For this, I’ll actually give on example how we expect this will be used in the standard library. Currently, the <a href="https://doc.rust-lang.org/stable/std/error/trait.Error.html"><code class="language-plaintext highlighter-rouge">Error</code> trait</a> is defined in <code class="language-plaintext highlighter-rouge">std</code>. It would be nice to move in to core. However, we want to write the following impls:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span> <span class="nb">From</span><span class="o">&lt;&amp;</span><span class="nb">str</span><span class="o">&gt;</span> <span class="k">for</span> <span class="nb">Box</span><span class="o">&lt;</span><span class="k">dyn</span> <span class="n">Error</span><span class="o">&gt;</span> <span class="p">{}</span>
<span class="k">impl</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="nb">From</span><span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="k">for</span> <span class="nb">Box</span><span class="o">&lt;</span><span class="k">dyn</span> <span class="n">Error</span><span class="o">&gt;</span> <span class="k">where</span> <span class="n">E</span><span class="p">:</span> <span class="n">Error</span> <span class="p">{}</span>
</code></pre></div></div>
<p>But we can’t, because we don’t know that <code class="language-plaintext highlighter-rouge">&amp;str: Error</code> will never hold (the way coherence in Rust works, upstream crates are allowed to add new impls). However, if we could add the following to core, it would be fine:</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">impl</span> <span class="o">!</span><span class="n">Error</span> <span class="k">for</span> <span class="o">&amp;</span><span class="nb">str</span> <span class="p">{}</span>
</code></pre></div></div>

<p>This feature allows that.</p>

<h4 id="contributions-3">Contributions</h4>

<p><a href="https://github.com/spastorino">Santiago Pastorino (spastorino)</a>
PRs: #90104</p>

<h2 id="other-work">Other work</h2>

<h3 id="projection-caching">Projection caching</h3>

<p>Without getting into the nitty-gritty details, there was a bug related to incremental compilation and associated type projection caching. Fixing that bug led to some severe performance problems in some cases, so there was additional followup work to fix that too.</p>

<p>Aaron1011: #85382, #85868, #88945, #88994, #89125, #89831, #90423, #92041
lcnr: #84944
the8472: #91186</p>

<h3 id="normalization-under-binders">Normalization under binders</h3>

<p>This work fixed a large class of ICEs that have existed since Rust’s infancy. The gist of it is that the following code would have problems.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="n">function</span><span class="o">&lt;</span><span class="n">F</span><span class="p">,</span> <span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">f</span><span class="p">:</span> <span class="n">F</span><span class="p">)</span>
<span class="k">where</span>
    <span class="n">F</span><span class="p">:</span> <span class="k">for</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;</span> <span class="nf">FnOnce</span><span class="p">(</span><span class="o">&lt;</span><span class="n">T</span> <span class="k">as</span> <span class="n">Trait</span><span class="o">&lt;</span><span class="nv">'a</span><span class="o">&gt;&gt;</span><span class="p">::</span><span class="n">Assoc</span><span class="p">),</span>
    <span class="n">T</span><span class="p">:</span> <span class="k">for</span><span class="o">&lt;</span><span class="nv">'b</span><span class="o">&gt;</span> <span class="n">Trait</span><span class="o">&lt;</span><span class="nv">'b</span><span class="o">&gt;</span> <span class="p">{}</span>
</code></pre></div></div>

<p>Basically, because of the <code class="language-plaintext highlighter-rouge">for&lt;'a&gt;</code>, the <code class="language-plaintext highlighter-rouge">&lt;T as Trait&lt;'a&gt;&gt;::Assoc</code> type could normalize in parts of rustc, but not in others.</p>

<p>jackh726: #85499, #90801, #90017, #89285, #88441, #86993</p>

<h3 id="tracking-binders">Tracking binders</h3>

<p>This is mostly an internal implementation detail in rustc. Essentially, it changes the way we track “bound variables”, like the <code class="language-plaintext highlighter-rouge">'a</code> in <code class="language-plaintext highlighter-rouge">for&lt;'a&gt; T: Trait&lt;'a&gt;</code>. Changing the way we track these didn’t, on its own, fix anything. However, it did identify some places where we were doing the wrong things and should hopefully make rustc more resilient to these bugs in the future. (It also likely is a prerequiste for Chalk integration.)</p>

<p>jackh726: #76814, #83870, #83944, #84377, #84559</p>

<h3 id="chalk">Chalk</h3>

<p>For those unfamiliar, <a href="https://github.com/rust-lang/chalk">Chalk</a> is essentially an implementation of the Rust trait system using a prolog-like solver. While progress here has somewhat slowed as we focus a bit on some rustc things (like GATs, TAITs, etc.), Chalk - and the fundamental idea of “formalizing” the type system and trait solver - remains a strong goal of the traits working group. I’ve tried to list all the people that contributed to Chalk in the latter half of 2020 and in 2021.</p>

<p>0xflotus, Aaron1011, Areredify, AzureMarker, daboross, HKalbasi, JakobDegen, LeSeulArtichaut, Veykril, basavesh, crlf0710, davidbarsky, detrumi, ectastic-morse, eggyal, ehuss, firefighterduck, flodiebold, henrikhorluck, jackh726, josh65536, lf-, matthewjasper, memoryleak47, memoryruins, nathanwit, nikomatsakis, nrc, pierwill, scalexm, spastorino, super-tuple, vandenheuvel</p>

<h2 id="concluding-words">Concluding words</h2>

<p>Again, I wish I had made this post earlier in the year. There’s already so much happening in 2022, and not talking about it is very difficult (though always feel free to reach out on Zulip if you’re interested). However, I <em>really</em> wanted to give credit to all the people above who have done great work.</p>]]></content><author><name></name></author><category term="rust" /><summary type="html"><![CDATA[So…this is awkward. I wanted to write this post near the end of 2021 or beginning of 2022, but time got away from me, as it does so often. However, a half-completed draft has been open in my browser this entire time, and I think it’d be a shame for it to go to waste and not celebrate all the work done on traits working-group related things and to celebrate the people who have done that amazing work. Given that this is “unofficial” though, I’ll be a little less formal than I otherwise would if this was posted to the Inside Rust Blog.]]></summary></entry><entry><title type="html">Rust 2021 - Stability</title><link href="https://jackhuey.me/rust/2020/10/01/rust-2021.html" rel="alternate" type="text/html" title="Rust 2021 - Stability" /><published>2020-10-01T14:00:00+00:00</published><updated>2020-10-01T14:00:00+00:00</updated><id>https://jackhuey.me/rust/2020/10/01/rust-2021</id><content type="html" xml:base="https://jackhuey.me/rust/2020/10/01/rust-2021.html"><![CDATA[<p>So. Hello! I’m Jack. And as it may or may not be obvious, this is my first blog post. I don’t want
to detract from the contents of this post too much, but I figured it’s at least worth a brief
explanation as to <em>why</em> I’m making it.</p>

<p>This is a response to the Rust <a href="https://blog.rust-lang.org/2020/09/03/Planning-2021-Roadmap.html">call for blog posts</a>
for 2021. Now, I do co-lead the <a href="https://rust-lang.github.io/wg-traits/">traits working group</a> and
have contributed to <a href="https://github.com/rust-lang/chalk">Chalk</a> a fair bit over the past year. But,
I do want to put a disclaimer that <em>the points I may make in this post are my own and I’m not
speaking in any “official” capacity here</em>. I wanted to make this post in case others find my
thoughts useful. And, frankly, I figured it would be fun.</p>

<p>Well, onto the contents of the post itself.</p>

<h2 id="background">Background</h2>

<p>Okay, let’s start with some background. My day job is actually being a graduate student
studying bioinformatics. In this field, it’s really a mixed bag of programming languages that you
see. Python and bash/shell scripts are extremely common for data munging, processing, etc. Python
also is used often for machine learning. R is used often for plotting, but also some data analysis.
Anytime you need more raw performance, you see a <em>lot</em> of C or sometimes C++. In the work I do, I
also heavily use Javscript/Typescript for web development, with a mixing of Kotlin. I use Rust for
one (unreleased) project, but that’s all so far.</p>

<p>A lot of the libraries and software for bioinformatics are used <em>because other people use them</em>;
they’ve been peer-reviewed and published, and as more people use them, the more of the <em>de facto</em>
standard they become. This isn’t bad necessarily: there are plenty of libraries and software that
are well-maintained, with easily-accesible source code, that does exactly what you need it to do.
But, there are also plenty of libraries and software that isn’t well-maintained, the source is hard
to find, or you need it to do something different.</p>

<p>Now, you might be asking: “how does this relate to Rust?” Well, in a way, it does and it doesn’t.
In some sense, the conclusion from the past couple paragraphs is “I want more libraries and software
for bioinformatics written in Rust.” But <em>why</em>? If you think the answer is “because I like the
language and like writing in it”, you would be partially correct. But, really, it’s because that I
think Rust has a lot to offer here:</p>

<p>Python and bash are generally okay for data munging and processing, but sometimes you really just
want some <em>type safety</em>. R is generally excellent for plotting, but…well I’m not even going to try
to list all the issues here. As far as data analysis tools written in R: have you ever had to hunt
down documentation, unsure of what exactly that function does? Something like rustdoc would be great
here. Performance-sensitive libraries and software are where I feel like Rust will shine the most;
I would probably be preaching to the choir here if I started to list off reasons why. And finally,
for web development related work, particularly server-side, it would be great to have better
predictability for the memory and CPU requirements needed.</p>

<p>Eek, that was a longer background than I expected. I guess the tldr is: I like Rust and I think it’s
a language that offers a lot of promise for many different types of applications. But, at least for
bioinformatics, there’s more work to be done to build up libraries.</p>

<h2 id="rust-2021">Rust 2021</h2>

<p>Now it’s time for the meat and potatoes: what I want to see from the Rust programming language in 2021.
I already mentioned in my background that I feel like more <strong>libraries</strong> are needed in Rust,
particularly around bioinformatics. But, in my opinion, <em>that will come in time</em>, and there’s not
much that can be done other than making the language something that the people <em>writing</em> those
libraries want to write in.</p>

<p>What I do want to talk about can maybe be summed up into a single word:
<strong>stability</strong>. This is very much a loaded word, but in this post, I’ll talk
about two separate parts of this.</p>

<h1 id="maturity-as-stability">Maturity as stability</h1>

<p>I recently saw a reddit post of someone asking about Rust’s stability. But, in
their post, they also said a different word: <em>mature</em>. What exactly <em>is</em> a
mature language? A mature library? Something that doesn’t add many new features?
Well, then surely C++ wouldn’t be called mature then (since there are numerous
new features in C++20, for example). One that doesn’t have a lot of bugs? Well,
good luck.</p>

<p>One way you could imagine maturity is like this: If the maintainers of the
language or library stopped working on it <em>today</em>, how bad would that be.
Under this definition, you can imagine something like the C language being very
mature; the core language hasn’t change much in a long time. A library that has
been written and does everything it’s supposed to without (more than perhaps a 
couple) bugs is probably considered mature. C++11? Probably mature. C++20?
Probably not. Maturity is <em>relative</em> and it’s <em>subjective</em>.</p>

<p>Maturity in a language is important. If you ask the question: “is this language
going to be around in 20 years”, the list of languages that you would feel a
confident “yes” for is probably small. In my opinion, Rust isn’t <em>quite</em> there,
<em>yet</em>. But what are some things that can be done to bring us there?</p>

<p>First, let’s think about the standard library. I want to make sure before I go
forward that the number of different APIs in std doesn’t exactly indicate it’s
maturity or not: a standard library with “all the batteries” doesn’t mean it’s
stable and a standard library without them doesn’t mean it’s not. Instead, std
maturity is more about having better knowledge of what programming patterns are
used often enough that they <em>should</em> be in std; and importantly, what <em>shouldn’t</em>
be. There are plenty of unstable library features where it’s up in the air
whether they should be stabilized or removed. And there are plenty of “wanted”
features that just aren’t in std yet. This is not to say there won’t <em>always</em>
be <em>some</em> API that someone wants, but I do feel like we’re still not quite
“mature”. Quick point though, I would say that 98% of the current std <em>is</em>
excellent and probably falls under the “mature” category.</p>

<p>Next, we can think about language features. There are number of features people
want to see: GATs, const generics, specialization all come to mind. In some form
or another, these each have <em>partial</em> implementations. There are other areas of
the language where the design hasn’t even been decided on (see the RFC
repository). Maturity here means pushing these language features through. It
means stabilizing pieces that work (e.g. <code class="language-plaintext highlighter-rouge">min_const_generics</code> or
<code class="language-plaintext highlighter-rouge">min_specialization</code>). It means working through the design of interacting with
bits and pieces of the language that today are somewhat “magic” (e.g.
traits/vtables or dynamically sized types). Of course, this can’t all happen in
2021, but that’s okay. It’s much better to get these designs <em>right</em> than to get
them <em>fast</em>. In 20 years, it isn’t going to matter if we had these features in
2021 or 2023.</p>

<p>Finally, libraries. A lot of libraries right now are <code class="language-plaintext highlighter-rouge">0.*</code>; i.e. they aren’t
committing to semver compatibility. Part of this is due to the previous two
points, but part of it isn’t. I would <em>really</em> like to see more libraries hit
<code class="language-plaintext highlighter-rouge">1.0</code>, but again <em>this will come in time</em>.</p>

<h1 id="librarification-as-stability">Librarification as stability</h1>

<p>Before I continue with this, I do want to point out that Niko Matsakis
previously wrote a <a href="http://smallcultfollowing.com/babysteps/blog/2020/04/09/libraryification/">great blog post</a>
covering some of this earlier this year. As he put it, “the basic idea is to refactor the compiler
into a set of <em>independent libraries</em>, all knit together by the query system.” In my view, this is
super important. In the blog post, he covers two points:</p>

<p>First, librarification can mean that tools can use the components of the
<em>rust compiler itself</em> to do analysis. For example,
<a href="https://github.com/rust-analyzer/rust-analyzer">rust-analyzer</a> could share the
type checker with rustc. This is great because it means that the tools to do static analysis, code
refactoring, etc. all become <em>better</em> or easier to implement. You wouldn’t have to worry “am I
covering all the types here” because the types you use are the types the <em>compiler</em> uses.</p>

<p>More importantly, in my opinion, librarification also means that each individial library is more
accesible than everything as a whole. The rustc codebase as it is now is…intimdating. There’s
been a huge surge of work fairly recently to help make it more accesible, but at least for now, the
compiler is still all together. Making the compiler more accessible to contributors is especially
important when you consider Rust in 20 years. It’s a much better idea to have people be able to pick
up parts of the compiler and contribute than to get stuck thinking of the compiler as a monolith.
This in particular is near and dear to my heart, because we have had so much success with this with
Chalk; this past year, we’ve had so much support, especially from people that don’t work on the
rustc codebase at all. I feel like it’s a model that really works well.</p>

<p>Let’s talk about Chalk though. For a quick summary for those who may not now: Chalk is an
implementation and definition of the Rust trait system using a PROLOG-like logic solver. The plan is
to eventually integrate it into the compiler as <em>the</em> trait solver. Currently, there is a
<em>very experimental</em> integration into rustc. <em>My</em> goal for Rust in 2021 is to get this integration to
a place that people can start playing with it. I’m definitely not committing to anything here, but
I’m super hopeful for this. And, I would love to start seeing other bits of the compiler start to be
split into libraries.</p>

<h2 id="summary">Summary</h2>

<p>Phew. That ended up being a lot. There’s more I could say. There’s so much praise I could give to
the Rust language and the people that contribute their time and energy to it, whether it be to the
compiler, the standard library, the docs, the libraries, the infrastructure, the community. At the
end of the day, I want to see this language grow. I want to see it <em>mature</em>. And ultimately, 2021 is
going to be another year of that. It’s been 5 years of Rust, so here’s to another 20+ more. 🥂</p>]]></content><author><name></name></author><category term="rust" /><summary type="html"><![CDATA[So. Hello! I’m Jack. And as it may or may not be obvious, this is my first blog post. I don’t want to detract from the contents of this post too much, but I figured it’s at least worth a brief explanation as to why I’m making it.]]></summary></entry></feed>