blob: 764e7f70a459059bfe948f8d46a46e5c1efbb571 [file] [log] [blame]
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Unsize and CoerceUnsized traits - 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/traits/unsize.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="coerceunsized"><a class="header" href="#coerceunsized"><a href="https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html"><code>CoerceUnsized</code></a></a></h1>
<p><code>CoerceUnsized</code> is primarily concerned with data containers. When a struct
(typically, a smart pointer) implements <code>CoerceUnsized</code>, that means that the
data it points to is being unsized.</p>
<p>Some implementors of <code>CoerceUnsized</code> include:</p>
<ul>
<li><code>&amp;T</code></li>
<li><code>Arc&lt;T&gt;</code></li>
<li><code>Box&lt;T&gt;</code></li>
</ul>
<p>This trait is (eventually) intended to be implemented by user-written smart
pointers, and there are rules about when a type is allowed to implement
<code>CoerceUnsized</code> that are explained in the trait's documentation.</p>
<h1 id="unsize"><a class="header" href="#unsize"><a href="https://doc.rust-lang.org/std/marker/trait.Unsize.html"><code>Unsize</code></a></a></h1>
<p>To contrast, the <code>Unsize</code> trait is concerned the actual types that are allowed
to be unsized.</p>
<p>This is not intended to be implemented by users ever, since <code>Unsize</code> does not
instruct the compiler (namely codegen) <em>how</em> to unsize a type, just whether it
is allowed to be unsized. This is paired somewhat intimately with codegen
which must understand how types are represented and unsized.</p>
<h2 id="primitive-unsizing-implementations"><a class="header" href="#primitive-unsizing-implementations">Primitive unsizing implementations</a></h2>
<p>Built-in implementations are provided for:</p>
<ul>
<li><code>T</code> -&gt; <code>dyn Trait + 'a</code> when <code>T: Trait</code> (and <code>T: Sized + 'a</code>, and <code>Trait</code>
is dyn-compatible<sup class="footnote-reference" id="fr-2-1"><a href="#footnote-2">1</a></sup>).</li>
<li><code>[T; N]</code> -&gt; <code>[T]</code></li>
</ul>
<h2 id="structural-implementations"><a class="header" href="#structural-implementations">Structural implementations</a></h2>
<p>There is one implementation of <code>Unsize</code> which can be thought of as
structural:</p>
<ul>
<li><code>Struct&lt;.., Pi, .., Pj, ..&gt;: Unsize&lt;Struct&lt;.., Ui, .., Uj, ..&gt;&gt;</code> given
<code>TailField&lt;Pi, .., Pj&gt;: Unsize&lt;Ui, .. Uj&gt;</code>, which allows the tail field of a
struct to be unsized if it is the only field that mentions generic parameters
<code>Pi</code>, .., <code>Pj</code> (which don't need to be contiguous).</li>
</ul>
<p>The rules for struct unsizing are slightly complicated, since they
may allow more than one parameter to be changed (not necessarily unsized) and
are best stated in terms of the tail field of the struct.</p>
<p>(Tuple unsizing was previously implemented behind the feature gate
<code>unsized_tuple_coercion</code>, but the implementation was removed by <a href="https://github.com/rust-lang/rust/pull/137728">#137728</a>.)</p>
<h2 id="upcasting-implementations"><a class="header" href="#upcasting-implementations">Upcasting implementations</a></h2>
<p>Two things are called "upcasting" internally:</p>
<ol>
<li>True upcasting <code>dyn SubTrait</code> -&gt; <code>dyn SuperTrait</code> (this also allows
dropping auto traits and adjusting lifetimes, as below).</li>
<li>Dropping auto traits and adjusting the lifetimes of dyn trait
<em>without changing the principal<sup class="footnote-reference" id="fr-1-1"><a href="#footnote-1">2</a></sup></em>:
<code>dyn Trait + AutoTraits... + 'a</code> -&gt; <code>dyn Trait + NewAutoTraits... + 'b</code>
when <code>AutoTraits</code><code>NewAutoTraits</code>, and <code>'a: 'b</code>.</li>
</ol>
<p>These may seem like different operations, since (1.) includes adjusting the
vtable of a dyn trait, while (2.) is a no-op. However, to the type system,
these are handled with much the same code.</p>
<p>This built-in implementation of <code>Unsize</code> is the most involved, particularly
after <a href="https://github.com/rust-lang/rust/pull/114036">it was reworked</a> to
support the complexities of associated types.</p>
<p>Specifically, the upcasting algorithm involves: For each supertrait of the
source dyn trait's principal (including itself)...</p>
<ol>
<li>Unify the super trait ref with the principal of the target (making sure
we only ever upcast to a true supertrait, and never <a href="https://github.com/rust-lang/rust/blob/f3457dbf84cd86d284454d12705861398ece76c3/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs#L19">via an impl</a>).</li>
<li>For every auto trait in the target, check that it's present in the source
(allowing us to drop auto traits, but never gain new ones).</li>
<li>For every projection in the target, check that it unifies with a single
projection in the source (since there may be more than one given
<code>trait Sub: Sup&lt;.., A = i32&gt; + Sup&lt;.., A = u32&gt;</code>).</li>
</ol>
<p>Specifically, (3.) prevents a choice of projection bound to guide inference
unnecessarily, though it may guide inference when it is unambiguous.</p>
<hr>
<ol class="footnote-definition"><li id="footnote-2">
<p>Formerly known as "object safe". <a href="#fr-2-1"></a></p>
</li>
<li id="footnote-1">
<p>The principal is the one non-auto trait of a <code>dyn Trait</code>. <a href="#fr-1-1"></a></p>
</li>
</ol>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../solve/significant-changes.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="../type-checking.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="../solve/significant-changes.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="../type-checking.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>