blob: efc95451a23859af2672feff1e7b3db2054c570c [file] [log] [blame] [edit]
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Lifetime parameters - Rust Compiler Development Guide</title>
<!-- Custom HTML head -->
<meta name="description" content="A guide to developing the Rust compiler (rustc)">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="../../favicon.svg">
<link rel="shortcut icon" href="../../favicon.png">
<link rel="stylesheet" href="../../css/variables.css">
<link rel="stylesheet" href="../../css/general.css">
<link rel="stylesheet" href="../../css/chrome.css">
<link rel="stylesheet" href="../../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="highlight-css" href="../../highlight.css">
<link rel="stylesheet" id="tomorrow-night-css" href="../../tomorrow-night.css">
<link rel="stylesheet" id="ayu-highlight-css" href="../../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="../../pagetoc.css">
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "../../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../../searchindex.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../../toc.js"></script>
</head>
<body>
<div id="mdbook-help-container">
<div id="mdbook-help-popup">
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
<div>
<p>Press <kbd></kbd> or <kbd></kbd> to navigate between chapters</p>
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
<p>Press <kbd>?</kbd> to show this help</p>
<p>Press <kbd>Esc</kbd> to hide this help</p>
</div>
</div>
</div>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
sidebar_toggle.checked = false;
}
if (sidebar === 'visible') {
sidebar_toggle.checked = true;
} else {
html.classList.remove('sidebar-visible');
}
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Rust Compiler Development Guide</h1>
<div class="right-buttons">
<a href="../../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/rust-lang/rustc-dev-guide" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/rust-lang/rustc-dev-guide/edit/main/src/borrow_check/region_inference/lifetime_parameters.md" title="Suggest an edit" aria-label="Suggest an edit" rel="edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<div class="search-wrapper">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
<div class="spinner-wrapper">
<i class="fa fa-spinner fa-spin"></i>
</div>
</div>
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="universal-regions"><a class="header" href="#universal-regions">Universal regions</a></h1>
<p>"Universal regions" is the name that the code uses to refer to "named
lifetimes" -- e.g., lifetime parameters and <code>'static</code>. The name
derives from the fact that such lifetimes are "universally quantified"
(i.e., we must make sure the code is true for all values of those
lifetimes). It is worth spending a bit of discussing how lifetime
parameters are handled during region inference. Consider this example:</p>
<pre><code class="language-rust ignore">fn foo&lt;'a, 'b&gt;(x: &amp;'a u32, y: &amp;'b u32) -&gt; &amp;'b u32 {
x
}</code></pre>
<p>This example is intended not to compile, because we are returning <code>x</code>,
which has type <code>&amp;'a u32</code>, but our signature promises that we will
return a <code>&amp;'b u32</code> value. But how are lifetimes like <code>'a</code> and <code>'b</code>
integrated into region inference, and how this error wind up being
detected?</p>
<h2 id="universal-regions-and-their-relationships-to-one-another"><a class="header" href="#universal-regions-and-their-relationships-to-one-another">Universal regions and their relationships to one another</a></h2>
<p>Early on in region inference, one of the first things we do is to
construct a <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/universal_regions/struct.UniversalRegions.html"><code>UniversalRegions</code></a> struct. This struct tracks the
various universal regions in scope on a particular function. We also
create a <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/type_check/free_region_relations/struct.UniversalRegionRelations.html"><code>UniversalRegionRelations</code></a> struct, which tracks their
relationships to one another. So if you have e.g. <code>where 'a: 'b</code>, then
the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/type_check/free_region_relations/struct.UniversalRegionRelations.html"><code>UniversalRegionRelations</code></a> struct would track that <code>'a: 'b</code> is
known to hold (which could be tested with the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/type_check/free_region_relations/struct.UniversalRegionRelations.html#method.outlives"><code>outlives</code></a> function).</p>
<h2 id="everything-is-a-region-variable"><a class="header" href="#everything-is-a-region-variable">Everything is a region variable</a></h2>
<p>One important aspect of how NLL region inference works is that <strong>all
lifetimes</strong> are represented as numbered variables. This means that the
only variant of <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/region_kind/enum.RegionKind.html"><code>region_kind::RegionKind</code></a> that we use is the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/region_kind/enum.RegionKind.html#variant.ReVar"><code>ReVar</code></a>
variant. These region variables are broken into two major categories,
based on their index:</p>
<ul>
<li>0..N: universal regions -- the ones we are discussing here. In this
case, the code must be correct with respect to any value of those
variables that meets the declared relationships.</li>
<li>N..M: existential regions -- inference variables where the region
inferencer is tasked with finding <em>some</em> suitable value.</li>
</ul>
<p>In fact, the universal regions can be further subdivided based on
where they were brought into scope (see the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/universal_regions/enum.RegionClassification.html#variant.Local"><code>RegionClassification</code></a>
type). These subdivisions are not important for the topics discussed
here, but become important when we consider <a href="./closure_constraints.html">closure constraint
propagation</a>, so we discuss them there.</p>
<h2 id="universal-lifetimes-as-the-elements-of-a-regions-value"><a class="header" href="#universal-lifetimes-as-the-elements-of-a-regions-value">Universal lifetimes as the elements of a region's value</a></h2>
<p>As noted previously, the value that we infer for each region is a set
<code>{E}</code>. The elements of this set can be points in the control-flow
graph, but they can also be an element <code>end('a)</code> corresponding to each
universal lifetime <code>'a</code>. If the value for some region <code>R0</code> includes
<code>end('a</code>), then this implies that <code>R0</code> must extend until the end of <code>'a</code>
in the caller.</p>
<h2 id="the-value-of-a-universal-region"><a class="header" href="#the-value-of-a-universal-region">The "value" of a universal region</a></h2>
<p>During region inference, we compute a value for each universal region
in the same way as we compute values for other regions. This value
represents, effectively, the <strong>lower bound</strong> on that universal region
-- the things that it must outlive. We now describe how we use this
value to check for errors.</p>
<h2 id="liveness-and-universal-regions"><a class="header" href="#liveness-and-universal-regions">Liveness and universal regions</a></h2>
<p>All universal regions have an initial liveness constraint that
includes the entire function body. This is because lifetime parameters
are defined in the caller and must include the entirety of the
function call that invokes this particular function. In addition, each
universal region <code>'a</code> includes itself (that is, <code>end('a)</code>) in its
liveness constraint (i.e., <code>'a</code> must extend until the end of
itself). In the code, these liveness constraints are setup in
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/region_infer/struct.RegionInferenceContext.html#method.init_free_and_bound_regions"><code>init_free_and_bound_regions</code></a>.</p>
<h2 id="propagating-outlives-constraints-for-universal-regions"><a class="header" href="#propagating-outlives-constraints-for-universal-regions">Propagating outlives constraints for universal regions</a></h2>
<p>So, consider the first example of this section:</p>
<pre><code class="language-rust ignore">fn foo&lt;'a, 'b&gt;(x: &amp;'a u32, y: &amp;'b u32) -&gt; &amp;'b u32 {
x
}</code></pre>
<p>Here, returning <code>x</code> requires that <code>&amp;'a u32 &lt;: &amp;'b u32</code>, which gives
rise to an outlives constraint <code>'a: 'b</code>. Combined with our default liveness
constraints we get:</p>
<pre><code class="language-txt">'a live at {B, end('a)} // B represents the "function body"
'b live at {B, end('b)}
'a: 'b
</code></pre>
<p>When we process the <code>'a: 'b</code> constraint, therefore, we will add
<code>end('b)</code> into the value for <code>'a</code>, resulting in a final value of <code>{B, end('a), end('b)}</code>.</p>
<h2 id="detecting-errors"><a class="header" href="#detecting-errors">Detecting errors</a></h2>
<p>Once we have finished constraint propagation, we then enforce a
constraint that if some universal region <code>'a</code> includes an element
<code>end('b)</code>, then <code>'a: 'b</code> must be declared in the function's bounds. If
not, as in our example, that is an error. This check is done in the
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/region_infer/struct.RegionInferenceContext.html#method.check_universal_regions"><code>check_universal_regions</code></a> function, which simply iterates over all
universal regions, inspects their final value, and tests against the
declared <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/type_check/free_region_relations/struct.UniversalRegionRelations.html"><code>UniversalRegionRelations</code></a>.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../../borrow_check/region_inference/constraint_propagation.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../../borrow_check/region_inference/member_constraints.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../../borrow_check/region_inference/constraint_propagation.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../../borrow_check/region_inference/member_constraints.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../../elasticlunr.min.js"></script>
<script src="../../mark.min.js"></script>
<script src="../../searcher.js"></script>
<script src="../../clipboard.min.js"></script>
<script src="../../highlight.js"></script>
<script src="../../book.js"></script>
<!-- Custom JS scripts -->
<script src="../../mermaid.min.js"></script>
<script src="../../mermaid-init.js"></script>
<script src="../../pagetoc.js"></script>
</div>
</body>
</html>