blob: 276034c521fc418cb36806e4a5affffc17d2d57e [file] [log] [blame]
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>The THIR (Typed High-level IR) - 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/thir.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="the-thir"><a class="header" href="#the-thir">The THIR</a></h1>
<p>The THIR ("Typed High-Level Intermediate Representation"), previously called HAIR for
"High-Level Abstract IR", is another IR used by rustc that is generated after
<a href="./type-checking.html">type checking</a>. It is (as of <!-- date-check --> January 2024) used for
<a href="./mir/construction.html">MIR construction</a>, <a href="./pat-exhaustive-checking.html">exhaustiveness checking</a>, and <a href="./unsafety-checking.html">unsafety checking</a>.</p>
<p>As the name might suggest, the THIR is a lowered version of the <a href="./hir.html">HIR</a> where all
the types have been filled in, which is possible after type checking has completed.
But it has some other interesting features that distinguish it from the HIR:</p>
<ul>
<li>
<p>Like the MIR, the THIR only represents bodies, i.e. "executable code"; this includes
function bodies, but also <code>const</code> initializers, for example. Specifically, all <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.BodyOwnerKind.html">body owners</a> have
THIR created. Consequently, the THIR has no representation for items like <code>struct</code>s or <code>trait</code>s.</p>
</li>
<li>
<p>Each body of THIR is only stored temporarily and is dropped as soon as it's no longer
needed, as opposed to being stored until the end of the compilation process (which
is what is done with the HIR).</p>
</li>
<li>
<p>Besides making the types of all nodes available, the THIR also has additional
desugaring compared to the HIR. For example, automatic references and dereferences
are made explicit, and method calls and overloaded operators are converted into
plain function calls. Destruction scopes are also made explicit.</p>
</li>
<li>
<p>Statements, expressions, and match arms are stored separately. For example, statements in the
<code>stmts</code> array reference expressions by their index (represented as a <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/thir/struct.ExprId.html"><code>ExprId</code></a>) in the <code>exprs</code>
array.</p>
</li>
</ul>
<p>The THIR lives in <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_build/thir/index.html"><code>rustc_mir_build::thir</code></a>. To construct a <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/thir/struct.Expr.html"><code>thir::Expr</code></a>,
you can use the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.thir_body"><code>thir_body</code></a> function, passing in the memory arena where the THIR
will be allocated. Dropping this arena will result in the THIR being destroyed,
which is useful to keep peak memory in check. Having a THIR representation of
all bodies of a crate in memory at the same time would be very heavy.</p>
<p>You can get a debug representation of the THIR by passing the <code>-Zunpretty=thir-tree</code> flag
to <code>rustc</code>.</p>
<p>To demonstrate, let's use the following example:</p>
<pre><pre class="playground"><code class="language-rust">fn main() {
let x = 1 + 2;
}</code></pre></pre>
<p>Here is how that gets represented in THIR (as of <!-- date-check --> Aug 2022):</p>
<pre><pre class="playground"><code class="language-rust no_run"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>Thir {
// no match arms
arms: [],
exprs: [
// expression 0, a literal with a value of 1
Expr {
ty: i32,
temp_lifetime: Some(
Node(1),
),
span: oneplustwo.rs:2:13: 2:14 (#0),
kind: Literal {
lit: Spanned {
node: Int(
1,
Unsuffixed,
),
span: oneplustwo.rs:2:13: 2:14 (#0),
},
neg: false,
},
},
// expression 1, scope surrounding literal 1
Expr {
ty: i32,
temp_lifetime: Some(
Node(1),
),
span: oneplustwo.rs:2:13: 2:14 (#0),
kind: Scope {
// reference to expression 0 above
region_scope: Node(3),
lint_level: Explicit(
HirId {
owner: DefId(0:3 ~ oneplustwo[6932]::main),
local_id: 3,
},
),
value: e0,
},
},
// expression 2, literal 2
Expr {
ty: i32,
temp_lifetime: Some(
Node(1),
),
span: oneplustwo.rs:2:17: 2:18 (#0),
kind: Literal {
lit: Spanned {
node: Int(
2,
Unsuffixed,
),
span: oneplustwo.rs:2:17: 2:18 (#0),
},
neg: false,
},
},
// expression 3, scope surrounding literal 2
Expr {
ty: i32,
temp_lifetime: Some(
Node(1),
),
span: oneplustwo.rs:2:17: 2:18 (#0),
kind: Scope {
region_scope: Node(4),
lint_level: Explicit(
HirId {
owner: DefId(0:3 ~ oneplustwo[6932]::main),
local_id: 4,
},
),
// reference to expression 2 above
value: e2,
},
},
// expression 4, represents 1 + 2
Expr {
ty: i32,
temp_lifetime: Some(
Node(1),
),
span: oneplustwo.rs:2:13: 2:18 (#0),
kind: Binary {
op: Add,
// references to scopes surrounding literals above
lhs: e1,
rhs: e3,
},
},
// expression 5, scope surrounding expression 4
Expr {
ty: i32,
temp_lifetime: Some(
Node(1),
),
span: oneplustwo.rs:2:13: 2:18 (#0),
kind: Scope {
region_scope: Node(5),
lint_level: Explicit(
HirId {
owner: DefId(0:3 ~ oneplustwo[6932]::main),
local_id: 5,
},
),
value: e4,
},
},
// expression 6, block around statement
Expr {
ty: (),
temp_lifetime: Some(
Node(9),
),
span: oneplustwo.rs:1:11: 3:2 (#0),
kind: Block {
body: Block {
targeted_by_break: false,
region_scope: Node(8),
opt_destruction_scope: None,
span: oneplustwo.rs:1:11: 3:2 (#0),
// reference to statement 0 below
stmts: [
s0,
],
expr: None,
safety_mode: Safe,
},
},
},
// expression 7, scope around block in expression 6
Expr {
ty: (),
temp_lifetime: Some(
Node(9),
),
span: oneplustwo.rs:1:11: 3:2 (#0),
kind: Scope {
region_scope: Node(9),
lint_level: Explicit(
HirId {
owner: DefId(0:3 ~ oneplustwo[6932]::main),
local_id: 9,
},
),
value: e6,
},
},
// destruction scope around expression 7
Expr {
ty: (),
temp_lifetime: Some(
Node(9),
),
span: oneplustwo.rs:1:11: 3:2 (#0),
kind: Scope {
region_scope: Destruction(9),
lint_level: Inherited,
value: e7,
},
},
],
stmts: [
// let statement
Stmt {
kind: Let {
remainder_scope: Remainder { block: 8, first_statement_index: 0},
init_scope: Node(1),
pattern: Pat {
ty: i32,
span: oneplustwo.rs:2:9: 2:10 (#0),
kind: Binding {
mutability: Not,
name: "x",
mode: ByValue,
var: LocalVarId(
HirId {
owner: DefId(0:3 ~ oneplustwo[6932]::main),
local_id: 7,
},
),
ty: i32,
subpattern: None,
is_primary: true,
},
},
initializer: Some(
e5,
),
else_block: None,
lint_level: Explicit(
HirId {
owner: DefId(0:3 ~ oneplustwo[6932]::main),
local_id: 6,
},
),
},
opt_destruction_scope: Some(
Destruction(1),
),
},
],
}
<span class="boring">}</span></code></pre></pre>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="hir/debugging.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="mir/index.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="hir/debugging.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="mir/index.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>