From cfe8e8561c2cc31ff51a298bc1dfd0636eaffa13 Mon Sep 17 00:00:00 2001 From: jyn Date: Sat, 20 May 2023 10:40:30 -0500 Subject: [PATCH 1/9] Make `x test --dry-run` less verbose Previously, this would print a message for each doctest, which was quite verbose: ``` doc tests for: /home/jyn/src/rust/src/doc/rustc/src/exploit-mitigations.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/instrument-coverage.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/json.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/linker-plugin-lto.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/lints/groups.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/lints/index.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/lints/levels.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/aarch64-nintendo-switch-freestanding.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/apple-watchos.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/armv4t-none-eabi.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/armv5te-none-eabi.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/esp-idf.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/fuchsia.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/kmc-solid.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/loongarch-linux.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/mipsel-sony-psx.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/nto-qnx.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/openbsd.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/openharmony.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/riscv32imac-unknown-xous-elf.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/unknown-uefi.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/platform-support/x86_64-unknown-none.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/profile-guided-optimization.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/target-tier-policy.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/targets/custom.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/targets/index.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/tests/index.md doc tests for: /home/jyn/src/rust/src/doc/rustc/src/what-is-rustc.md ``` --- src/bootstrap/test.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 2d600704e025e..27b1f76a0692c 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1796,6 +1796,14 @@ impl Step for BookTest { /// /// This uses the `rustdoc` that sits next to `compiler`. fn run(self, builder: &Builder<'_>) { + let host = self.compiler.host; + let _guard = builder.msg( + Kind::Test, + self.compiler.stage, + &format!("book {}", self.name), + host, + host, + ); // External docs are different from local because: // - Some books need pre-processing by mdbook before being tested. // - They need to save their state to toolstate. @@ -1987,7 +1995,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> } } - builder.info(&format!("doc tests for: {}", markdown.display())); + builder.verbose(&format!("doc tests for: {}", markdown.display())); let mut cmd = builder.rustdoc_cmd(compiler); builder.add_rust_test_threads(&mut cmd); // allow for unstable options such as new editions From c1d72de030f3c1287a363ff7cb134664a6bf3032 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 23 May 2023 15:29:43 -0700 Subject: [PATCH 2/9] rustdoc: add interaction delays for tooltip popovers Designing a good hover microinteraction is a matter of guessing user intent from what are, literally, vague gestures. In this case, guessing if hovering in our out of the tooltip base is intentional or not. To figure this out, a few different techniques are used: * When the mouse pointer enters a tooltip anchor point, its hitbox is grown on the bottom, where the popover is/will appear. This was already there before this commit: search "hover tunnel" in rustdoc.css for the implementation. * This commit adds a delay when the mouse pointer enters the base anchor, in case the mouse pointer was just passing through and the user didn't want to open it. * This commit also adds a delay when the mouse pointer exits the tooltip's base anchor or its popover, before hiding it. * A fade-out animation is layered onto the pointer exit delay to immediately inform the user that they successfully dismissed the popover, while still providing a way for them to cancel it if it was a mistake and they still wanted to interact with it. * No animation is used for revealing it, because we don't want people to try to interact with an element while it's in the middle of fading in: either they're allowed to interact with it while it's fading in, meaning it can't serve as mistake- proofing for opening the popover, or they can't, but they might try and be frustrated. See also: * https://www.nngroup.com/articles/timing-exposing-content/ * https://www.nngroup.com/articles/tooltip-guidelines/ * https://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown --- src/librustdoc/html/static/css/rustdoc.css | 8 ++ src/librustdoc/html/static/js/main.js | 113 +++++++++++++++++++-- tests/rustdoc-gui/codeblock-tooltip.goml | 2 + tests/rustdoc-gui/notable-trait.goml | 2 +- 4 files changed, 115 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index a7d5f497756b5..cd5ff48c97991 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1191,6 +1191,14 @@ a.tooltip:hover::after { content: "\00a0"; } +/* This animation is layered onto the mistake-proofing delay for dismissing + a hovered tooltip, to ensure it feels responsive even with the delay. + */ +.fade-out { + opacity: 0; + transition: opacity 0.45s cubic-bezier(0, 0, 0.1, 1.0); +} + .popover.tooltip .content { margin: 0.25em 0.5em; } diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index bccf675c14b5e..11ed2f5f9017c 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -4,6 +4,13 @@ "use strict"; +// The amount of time that the cursor must remain still over a hover target before +// revealing a tooltip. +// +// https://www.nngroup.com/articles/timing-exposing-content/ +window.RUSTDOC_TOOLTIP_HOVER_MS = 300; +window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS = 450; + // Given a basename (e.g. "storage") and an extension (e.g. ".js"), return a URL // for a resource under the root-path, with the resource-suffix. function resourcePath(basename, extension) { @@ -784,6 +791,7 @@ function preLoadCss(cssUrl) { } if (window.CURRENT_TOOLTIP_ELEMENT && window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE === e) { // Make this function idempotent. + clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT); return; } window.hideAllModals(false); @@ -791,11 +799,17 @@ function preLoadCss(cssUrl) { if (notable_ty) { wrapper.innerHTML = "
" + window.NOTABLE_TRAITS[notable_ty] + "
"; - } else if (e.getAttribute("title") !== undefined) { - const titleContent = document.createElement("div"); - titleContent.className = "content"; - titleContent.appendChild(document.createTextNode(e.getAttribute("title"))); - wrapper.appendChild(titleContent); + } else { + if (e.getAttribute("title") !== null) { + e.setAttribute("data-title", e.getAttribute("title")); + e.removeAttribute("title"); + } + if (e.getAttribute("data-title") !== null) { + const titleContent = document.createElement("div"); + titleContent.className = "content"; + titleContent.appendChild(document.createTextNode(e.getAttribute("data-title"))); + wrapper.appendChild(titleContent); + } } wrapper.className = "tooltip popover"; const focusCatcher = document.createElement("div"); @@ -824,17 +838,59 @@ function preLoadCss(cssUrl) { wrapper.style.visibility = ""; window.CURRENT_TOOLTIP_ELEMENT = wrapper; window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE = e; + clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT); + wrapper.onpointerenter = function(ev) { + // If this is a synthetic touch event, ignore it. A click event will be along shortly. + if (ev.pointerType !== "mouse") { + return; + } + clearTooltipHoverTimeout(e); + }; wrapper.onpointerleave = function(ev) { // If this is a synthetic touch event, ignore it. A click event will be along shortly. if (ev.pointerType !== "mouse") { return; } - if (!e.TOOLTIP_FORCE_VISIBLE && !elemIsInParent(event.relatedTarget, e)) { - hideTooltip(true); + if (!e.TOOLTIP_FORCE_VISIBLE && !elemIsInParent(ev.relatedTarget, e)) { + // See "Tooltip pointer leave gesture" below. + setTooltipHoverTimeout(e, false); + addClass(wrapper, "fade-out"); } }; } + function setTooltipHoverTimeout(element, show) { + clearTooltipHoverTimeout(element); + if (!show && !window.CURRENT_TOOLTIP_ELEMENT) { + // To "hide" an already hidden element, just cancel its timeout. + return; + } + if (show && window.CURRENT_TOOLTIP_ELEMENT) { + // To "show" an already visible element, just cancel its timeout. + return; + } + if (window.CURRENT_TOOLTIP_ELEMENT && + window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE !== element) { + // Don't do anything if another tooltip is already visible. + return; + } + element.TOOLTIP_HOVER_TIMEOUT = setTimeout(() => { + if (show) { + showTooltip(element); + } else if (!element.TOOLTIP_FORCE_VISIBLE) { + hideTooltip(false); + } + }, show ? window.RUSTDOC_TOOLTIP_HOVER_MS : window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS); + } + + function clearTooltipHoverTimeout(element) { + if (element.TOOLTIP_HOVER_TIMEOUT !== undefined) { + removeClass(window.CURRENT_TOOLTIP_ELEMENT, "fade-out"); + clearTimeout(element.TOOLTIP_HOVER_TIMEOUT); + delete element.TOOLTIP_HOVER_TIMEOUT; + } + } + function tooltipBlurHandler(event) { if (window.CURRENT_TOOLTIP_ELEMENT && !elemIsInParent(document.activeElement, window.CURRENT_TOOLTIP_ELEMENT) && @@ -864,6 +920,7 @@ function preLoadCss(cssUrl) { } const body = document.getElementsByTagName("body")[0]; body.removeChild(window.CURRENT_TOOLTIP_ELEMENT); + clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT); window.CURRENT_TOOLTIP_ELEMENT = null; } } @@ -886,7 +943,14 @@ function preLoadCss(cssUrl) { if (ev.pointerType !== "mouse") { return; } - showTooltip(this); + setTooltipHoverTimeout(this, true); + }; + e.onpointermove = function(ev) { + // If this is a synthetic touch event, ignore it. A click event will be along shortly. + if (ev.pointerType !== "mouse") { + return; + } + setTooltipHoverTimeout(this, true); }; e.onpointerleave = function(ev) { // If this is a synthetic touch event, ignore it. A click event will be along shortly. @@ -895,7 +959,38 @@ function preLoadCss(cssUrl) { } if (!this.TOOLTIP_FORCE_VISIBLE && !elemIsInParent(ev.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT)) { - hideTooltip(true); + // Tooltip pointer leave gesture: + // + // Designing a good hover microinteraction is a matter of guessing user + // intent from what are, literally, vague gestures. In this case, guessing if + // hovering in or out of the tooltip base is intentional or not. + // + // To figure this out, a few different techniques are used: + // + // * When the mouse pointer enters a tooltip anchor point, its hitbox is grown + // on the bottom, where the popover is/will appear. Search "hover tunnel" in + // rustdoc.css for the implementation. + // * There's a delay when the mouse pointer enters the popover base anchor, in + // case the mouse pointer was just passing through and the user didn't want + // to open it. + // * Similarly, a delay is added when exiting the anchor, or the popover + // itself, before hiding it. + // * A fade-out animation is layered onto the pointer exit delay to immediately + // inform the user that they successfully dismissed the popover, while still + // providing a way for them to cancel it if it was a mistake and they still + // wanted to interact with it. + // * No animation is used for revealing it, because we don't want people to try + // to interact with an element while it's in the middle of fading in: either + // they're allowed to interact with it while it's fading in, meaning it can't + // serve as mistake-proofing for the popover, or they can't, but + // they might try and be frustrated. + // + // See also: + // * https://www.nngroup.com/articles/timing-exposing-content/ + // * https://www.nngroup.com/articles/tooltip-guidelines/ + // * https://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown + setTooltipHoverTimeout(e, false); + addClass(window.CURRENT_TOOLTIP_ELEMENT, "fade-out"); } }; }); diff --git a/tests/rustdoc-gui/codeblock-tooltip.goml b/tests/rustdoc-gui/codeblock-tooltip.goml index e1c81ed79e401..7be5e39ba4727 100644 --- a/tests/rustdoc-gui/codeblock-tooltip.goml +++ b/tests/rustdoc-gui/codeblock-tooltip.goml @@ -40,6 +40,7 @@ define-function: ( "background-color": |background|, "border-color": |border|, }) + click: ".docblock .example-wrap.compile_fail .tooltip" // should_panic block assert-css: ( @@ -71,6 +72,7 @@ define-function: ( "background-color": |background|, "border-color": |border|, }) + click: ".docblock .example-wrap.should_panic .tooltip" // ignore block assert-css: ( diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml index ecb57c274a5d3..09b3dfe282516 100644 --- a/tests/rustdoc-gui/notable-trait.goml +++ b/tests/rustdoc-gui/notable-trait.goml @@ -134,7 +134,7 @@ define-function: ( reload: move-cursor-to: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" - assert-count: (".tooltip.popover", 1) + wait-for-count: (".tooltip.popover", 1) assert-css: ( ".tooltip.popover h3", From b9302d72346444b74bfbb2274c6da1acda9622a7 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 23 May 2023 17:19:35 -0700 Subject: [PATCH 3/9] rustdoc: add hover indicator for notable trait tooltip --- src/librustdoc/html/static/css/rustdoc.css | 4 ++++ tests/rustdoc-gui/notable-trait.goml | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index cd5ff48c97991..054cfe7597ea5 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1179,6 +1179,10 @@ a.test-arrow:hover { position: relative; } +.code-header a.tooltip:hover { + color: var(--link-color); +} + /* placeholder thunk so that the mouse can easily travel from "(i)" to popover the resulting "hover tunnel" is a stepped triangle, approximating https://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown */ diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml index 09b3dfe282516..371931d51fccc 100644 --- a/tests/rustdoc-gui/notable-trait.goml +++ b/tests/rustdoc-gui/notable-trait.goml @@ -122,7 +122,7 @@ assert-count: ("//*[@class='tooltip popover']", 0) // Now check the colors. define-function: ( "check-colors", - (theme, header_color, content_color, type_color, trait_color), + (theme, header_color, content_color, type_color, trait_color, link_color), block { go-to: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html" // This is needed to ensure that the text color is computed. @@ -133,9 +133,21 @@ define-function: ( // We reload the page so the local storage settings are being used. reload: + assert-css: ( + "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", + {"color": |content_color|}, + ALL, + ) + move-cursor-to: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']" wait-for-count: (".tooltip.popover", 1) + assert-css: ( + "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']", + {"color": |link_color|}, + ALL, + ) + assert-css: ( ".tooltip.popover h3", {"color": |header_color|}, @@ -163,6 +175,7 @@ call-function: ( "check-colors", { "theme": "ayu", + "link_color": "rgb(57, 175, 215)", "content_color": "rgb(230, 225, 207)", "header_color": "rgb(255, 255, 255)", "type_color": "rgb(255, 160, 165)", @@ -174,6 +187,7 @@ call-function: ( "check-colors", { "theme": "dark", + "link_color": "rgb(210, 153, 29)", "content_color": "rgb(221, 221, 221)", "header_color": "rgb(221, 221, 221)", "type_color": "rgb(45, 191, 184)", @@ -185,6 +199,7 @@ call-function: ( "check-colors", { "theme": "light", + "link_color": "rgb(56, 115, 173)", "content_color": "rgb(0, 0, 0)", "header_color": "rgb(0, 0, 0)", "type_color": "rgb(173, 55, 138)", From 9dedb43e876832143ded6a2737c969c4a6e73296 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 31 May 2023 13:03:46 +0200 Subject: [PATCH 4/9] Migrate GUI colors test to original CSS color format --- tests/rustdoc-gui/theme-in-history.goml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/rustdoc-gui/theme-in-history.goml b/tests/rustdoc-gui/theme-in-history.goml index 8fcd0ecd3094b..42c5b5e6e69e3 100644 --- a/tests/rustdoc-gui/theme-in-history.goml +++ b/tests/rustdoc-gui/theme-in-history.goml @@ -7,7 +7,7 @@ set-local-storage: { } // We reload the page so the local storage settings are being used. reload: -assert-css: ("body", { "background-color": "rgb(53, 53, 53)" }) +assert-css: ("body", { "background-color": "#353535" }) assert-local-storage: { "rustdoc-theme": "dark" } // Now we go to the settings page. @@ -15,7 +15,7 @@ go-to: "file://" + |DOC_PATH| + "/settings.html" wait-for: "#settings" // We change the theme to "light". click: "#theme-light" -wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" }) +wait-for-css: ("body", { "background-color": "white" }) assert-local-storage: { "rustdoc-theme": "light" } // We go back in history. @@ -23,5 +23,5 @@ history-go-back: // Confirm that we're not on the settings page. assert-false: "#settings" // Check that the current theme is still "light". -assert-css: ("body", { "background-color": "rgb(255, 255, 255)" }) +assert-css: ("body", { "background-color": "white" }) assert-local-storage: { "rustdoc-theme": "light" } From cc21d9aa522cf07148e154ce9aec5f5f7a67c86c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 31 May 2023 14:42:54 +1000 Subject: [PATCH 5/9] Don't compute inlining status of mono items in advance. We record inlining status for mono items in `MonoItems`, and then transfer it to `InliningMap`, for later use in `InliningMap::with_inlining_candidates`. But we can just compute inlining status directly in `InliningMap::with_inlining_candidates`, because the mono item is right there. There's no need to compute it in advance. This commit changes the code to do that, removing the need for `MonoItems` and `InliningMap::inlines`. This does result in more calls to `instantiation_mode` (one per static occurrence) but the performance effect is negligible. --- compiler/rustc_monomorphize/src/collector.rs | 76 ++++--------------- .../rustc_monomorphize/src/partitioning.rs | 7 +- 2 files changed, 17 insertions(+), 66 deletions(-) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index cefa64d27acba..09025c1ee3319 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -179,7 +179,6 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::lang_items::LangItem; -use rustc_index::bit_set::GrowableBitSet; use rustc_middle::mir::interpret::{AllocId, ConstValue}; use rustc_middle::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar}; use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; @@ -220,78 +219,29 @@ pub struct InliningMap<'tcx> { // The range selects elements within the `targets` vecs. index: FxHashMap, Range>, targets: Vec>, - - // Contains one bit per mono item in the `targets` field. That bit - // is true if that mono item needs to be inlined into every CGU. - inlines: GrowableBitSet, -} - -/// Struct to store mono items in each collecting and if they should -/// be inlined. We call `instantiation_mode` to get their inlining -/// status when inserting new elements, which avoids calling it in -/// `inlining_map.lock_mut()`. See the `collect_items_rec` implementation -/// below. -struct MonoItems<'tcx> { - // If this is false, we do not need to compute whether items - // will need to be inlined. - compute_inlining: bool, - - // The TyCtxt used to determine whether the a item should - // be inlined. - tcx: TyCtxt<'tcx>, - - // The collected mono items. The bool field in each element - // indicates whether this element should be inlined. - items: Vec<(Spanned>, bool /*inlined*/)>, } -impl<'tcx> MonoItems<'tcx> { - #[inline] - fn push(&mut self, item: Spanned>) { - self.extend([item]); - } - - #[inline] - fn extend>>>(&mut self, iter: T) { - self.items.extend(iter.into_iter().map(|mono_item| { - let inlined = if !self.compute_inlining { - false - } else { - mono_item.node.instantiation_mode(self.tcx) == InstantiationMode::LocalCopy - }; - (mono_item, inlined) - })) - } -} +type MonoItems<'tcx> = Vec>>; impl<'tcx> InliningMap<'tcx> { fn new() -> InliningMap<'tcx> { - InliningMap { - index: FxHashMap::default(), - targets: Vec::new(), - inlines: GrowableBitSet::with_capacity(1024), - } + InliningMap { index: FxHashMap::default(), targets: Vec::new() } } fn record_accesses<'a>( &mut self, source: MonoItem<'tcx>, - new_targets: &'a [(Spanned>, bool)], + new_targets: &'a [Spanned>], ) where 'tcx: 'a, { let start_index = self.targets.len(); let new_items_count = new_targets.len(); - let new_items_count_total = new_items_count + self.targets.len(); self.targets.reserve(new_items_count); - self.inlines.ensure(new_items_count_total); - for (i, (Spanned { node: mono_item, .. }, inlined)) in new_targets.into_iter().enumerate() { + for Spanned { node: mono_item, .. } in new_targets.into_iter() { self.targets.push(*mono_item); - if *inlined { - self.inlines.insert(i + start_index); - } } let end_index = self.targets.len(); @@ -300,13 +250,14 @@ impl<'tcx> InliningMap<'tcx> { /// Internally iterate over all items referenced by `source` which will be /// made available for inlining. - pub fn with_inlining_candidates(&self, source: MonoItem<'tcx>, mut f: F) + pub fn with_inlining_candidates(&self, tcx: TyCtxt<'tcx>, source: MonoItem<'tcx>, mut f: F) where F: FnMut(MonoItem<'tcx>), { if let Some(range) = self.index.get(&source) { - for (i, candidate) in self.targets[range.clone()].iter().enumerate() { - if self.inlines.contains(range.start + i) { + for candidate in self.targets[range.clone()].iter() { + let is_inlined = candidate.instantiation_mode(tcx) == InstantiationMode::LocalCopy; + if is_inlined { f(*candidate); } } @@ -367,7 +318,7 @@ pub fn collect_crate_mono_items( #[instrument(skip(tcx, mode), level = "debug")] fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec> { debug!("collecting roots"); - let mut roots = MonoItems { compute_inlining: false, tcx, items: Vec::new() }; + let mut roots = Vec::new(); { let entry_fn = tcx.entry_fn(()); @@ -393,9 +344,8 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec( return; } - let mut neighbors = MonoItems { compute_inlining: true, tcx, items: Vec::new() }; + let mut neighbors = Vec::new(); let recursion_depth_reset; // @@ -542,9 +492,9 @@ fn collect_items_rec<'tcx>( formatted_item, }); } - inlining_map.lock_mut().record_accesses(starting_point.node, &neighbors.items); + inlining_map.lock_mut().record_accesses(starting_point.node, &neighbors); - for (neighbour, _) in neighbors.items { + for neighbour in neighbors { collect_items_rec(tcx, neighbour, visited, recursion_depths, recursion_limit, inlining_map); } diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index be9c349c38416..0bacb58383dc0 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -424,7 +424,7 @@ fn place_inlined_mono_items<'tcx>( // Collect all items that need to be available in this codegen unit. let mut reachable = FxHashSet::default(); for root in old_codegen_unit.items().keys() { - follow_inlining(*root, cx.inlining_map, &mut reachable); + follow_inlining(cx.tcx, *root, cx.inlining_map, &mut reachable); } let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); @@ -478,6 +478,7 @@ fn place_inlined_mono_items<'tcx>( return mono_item_placements; fn follow_inlining<'tcx>( + tcx: TyCtxt<'tcx>, mono_item: MonoItem<'tcx>, inlining_map: &InliningMap<'tcx>, visited: &mut FxHashSet>, @@ -486,8 +487,8 @@ fn place_inlined_mono_items<'tcx>( return; } - inlining_map.with_inlining_candidates(mono_item, |target| { - follow_inlining(target, inlining_map, visited); + inlining_map.with_inlining_candidates(tcx, mono_item, |target| { + follow_inlining(tcx, target, inlining_map, visited); }); } } From 2eeb7693c5cb2e324458094bc8e923489a318953 Mon Sep 17 00:00:00 2001 From: anna-singleton Date: Wed, 31 May 2023 15:51:28 +0100 Subject: [PATCH 6/9] remove reference to Into in ? operator core/std docs, fix 111655 --- library/core/src/convert/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 38a6d1ccdb552..799085e9a8307 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -495,8 +495,7 @@ pub trait Into: Sized { /// By converting underlying error types to our own custom error type that encapsulates the /// underlying error type, we can return a single error type without losing information on the /// underlying cause. The '?' operator automatically converts the underlying error type to our -/// custom error type by calling `Into::into` which is automatically provided when -/// implementing `From`. The compiler then infers which implementation of `Into` should be used. +/// custom error type with `From::from`. /// /// ``` /// use std::fs; From e8c831a03b4448a1b380cb26394e036f240ce6c2 Mon Sep 17 00:00:00 2001 From: Ziru Niu Date: Thu, 1 Jun 2023 01:16:03 +0800 Subject: [PATCH 7/9] add inline-const test for elided lifetimes being infer vars --- .../inline-const/elided-lifetime-being-infer-vars.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/ui/inline-const/elided-lifetime-being-infer-vars.rs diff --git a/tests/ui/inline-const/elided-lifetime-being-infer-vars.rs b/tests/ui/inline-const/elided-lifetime-being-infer-vars.rs new file mode 100644 index 0000000000000..5661db4a2530d --- /dev/null +++ b/tests/ui/inline-const/elided-lifetime-being-infer-vars.rs @@ -0,0 +1,11 @@ +// check-pass + +#![feature(inline_const)] + +fn main() { + let _my_usize = const { + let a = 10_usize; + let b: &'_ usize = &a; + *b + }; +} From d7d497a3c11ea7dc764d0f8d58a2a15cb395f5e9 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 31 May 2023 16:55:59 -0700 Subject: [PATCH 8/9] rustdoc: add jsdoc comments for complex functions --- src/librustdoc/html/static/js/main.js | 35 ++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 11ed2f5f9017c..6da51ea0a55e7 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -779,6 +779,13 @@ function preLoadCss(cssUrl) { }); }); + /** + * Show a tooltip immediately. + * + * @param {DOMElement} e - The tooltip's anchor point. The DOM is consulted to figure + * out what the tooltip should contain, and where it should be + * positioned. + */ function showTooltip(e) { const notable_ty = e.getAttribute("data-notable-ty"); if (!window.NOTABLE_TRAITS && notable_ty) { @@ -789,8 +796,9 @@ function preLoadCss(cssUrl) { throw new Error("showTooltip() called with notable without any notable traits!"); } } + // Make this function idempotent. If the tooltip is already shown, avoid doing extra work + // and leave it alone. if (window.CURRENT_TOOLTIP_ELEMENT && window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE === e) { - // Make this function idempotent. clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT); return; } @@ -800,6 +808,7 @@ function preLoadCss(cssUrl) { wrapper.innerHTML = "
" + window.NOTABLE_TRAITS[notable_ty] + "
"; } else { + // Replace any `title` attribute with `data-title` to avoid double tooltips. if (e.getAttribute("title") !== null) { e.setAttribute("data-title", e.getAttribute("title")); e.removeAttribute("title"); @@ -859,6 +868,17 @@ function preLoadCss(cssUrl) { }; } + /** + * Show or hide the tooltip after a timeout. If a timeout was already set before this function + * was called, that timeout gets cleared. If the tooltip is already in the requested state, + * this function will still clear any pending timeout, but otherwise do nothing. + * + * @param {DOMElement} element - The tooltip's anchor point. The DOM is consulted to figure + * out what the tooltip should contain, and where it should be + * positioned. + * @param {boolean} show - If true, the tooltip will be made visible. If false, it will + * be hidden. + */ function setTooltipHoverTimeout(element, show) { clearTooltipHoverTimeout(element); if (!show && !window.CURRENT_TOOLTIP_ELEMENT) { @@ -883,6 +903,13 @@ function preLoadCss(cssUrl) { }, show ? window.RUSTDOC_TOOLTIP_HOVER_MS : window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS); } + /** + * If a show/hide timeout was set by `setTooltipHoverTimeout`, cancel it. If none exists, + * do nothing. + * + * @param {DOMElement} element - The tooltip's anchor point, + * as passed to `setTooltipHoverTimeout`. + */ function clearTooltipHoverTimeout(element) { if (element.TOOLTIP_HOVER_TIMEOUT !== undefined) { removeClass(window.CURRENT_TOOLTIP_ELEMENT, "fade-out"); @@ -910,6 +937,12 @@ function preLoadCss(cssUrl) { } } + /** + * Hide the current tooltip immediately. + * + * @param {boolean} focus - If set to `true`, move keyboard focus to the tooltip anchor point. + * If set to `false`, leave keyboard focus alone. + */ function hideTooltip(focus) { if (window.CURRENT_TOOLTIP_ELEMENT) { if (window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE) { From 1293c1720574144ec13df2bbdcf26dab8e3b771f Mon Sep 17 00:00:00 2001 From: Shane Murphy Date: Wed, 31 May 2023 17:22:44 -0700 Subject: [PATCH 9/9] Fix bug in utf16_to_utf8 for zero length strings This fixes the behavior of sending EOF by pressing Ctrl+Z => Enter in a windows console. Previously, that would trip the unpaired surrogate error, whereas now we correctly detect EOF. --- library/std/src/sys/windows/stdio.rs | 7 +++++++ library/std/src/sys/windows/stdio/tests.rs | 6 ++++++ 2 files changed, 13 insertions(+) create mode 100644 library/std/src/sys/windows/stdio/tests.rs diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs index 2e3e0859dc18e..3fcaaa508e3c8 100644 --- a/library/std/src/sys/windows/stdio.rs +++ b/library/std/src/sys/windows/stdio.rs @@ -11,6 +11,9 @@ use crate::sys::cvt; use crate::sys::handle::Handle; use core::str::utf8_char_width; +#[cfg(test)] +mod tests; + // Don't cache handles but get them fresh for every read/write. This allows us to track changes to // the value over time (such as if a process calls `SetStdHandle` while it's running). See #40490. pub struct Stdin { @@ -383,6 +386,10 @@ fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result { debug_assert!(utf16.len() <= c::c_int::MAX as usize); debug_assert!(utf8.len() <= c::c_int::MAX as usize); + if utf16.is_empty() { + return Ok(0); + } + let result = unsafe { c::WideCharToMultiByte( c::CP_UTF8, // CodePage diff --git a/library/std/src/sys/windows/stdio/tests.rs b/library/std/src/sys/windows/stdio/tests.rs new file mode 100644 index 0000000000000..1e53e0bee6369 --- /dev/null +++ b/library/std/src/sys/windows/stdio/tests.rs @@ -0,0 +1,6 @@ +use super::utf16_to_utf8; + +#[test] +fn zero_size_read() { + assert_eq!(utf16_to_utf8(&[], &mut []).unwrap(), 0); +}