about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-10-17 17:05:17 +0000
committerbors <bors@rust-lang.org>2022-10-17 17:05:17 +0000
commit9c2797de2214f5c2feeca2c466cdd3236530a2b0 (patch)
tree5ec9c17bd6f6e53470b9c9c5db3a00310a587dd8
parenta9d1cafa878ecc04a4aa7aaa7df0414a29a2bd0b (diff)
parente1d72a485a716905560e567c8d2e2a2dbc705341 (diff)
downloadrust-9c2797de2214f5c2feeca2c466cdd3236530a2b0.tar.gz
rust-9c2797de2214f5c2feeca2c466cdd3236530a2b0.zip
Auto merge of #103151 - matthiaskrgr:rollup-t3mmnsg, r=matthiaskrgr
Rollup of 4 pull requests

Successful merges:

 - #102454 (Suggest parentheses for possible range method calling)
 - #102466 (only allow `ConstEquate` with `feature(gce)`)
 - #102945 (Do not register placeholder `RegionOutlives` obligations when `considering_regions` is false)
 - #103091 (rustdoc: remove unused HTML class `sidebar-title`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl4
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/suggest.rs89
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs26
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs27
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs24
-rw-r--r--src/librustdoc/html/render/mod.rs8
-rw-r--r--src/test/rustdoc-gui/sidebar-mobile.goml2
-rw-r--r--src/test/rustdoc/associated-consts.rs8
-rw-r--r--src/test/rustdoc/deref-recursive-pathbuf.rs4
-rw-r--r--src/test/rustdoc/deref-recursive.rs4
-rw-r--r--src/test/rustdoc/deref-typedef.rs2
-rw-r--r--src/test/rustdoc/escape-deref-methods.rs2
-rw-r--r--src/test/rustdoc/negative-impl-sidebar.rs2
-rw-r--r--src/test/rustdoc/sidebar-items.rs18
-rw-r--r--src/test/rustdoc/sidebar-links-to-foreign-impl.rs2
-rw-r--r--src/test/rustdoc/tuple-struct-fields-doc.rs2
-rw-r--r--src/test/ui/higher-rank-trait-bounds/issue-100689.rs29
-rw-r--r--src/test/ui/higher-rank-trait-bounds/issue-102899.rs32
-rw-r--r--src/test/ui/methods/issues/issue-90315.rs79
-rw-r--r--src/test/ui/methods/issues/issue-90315.stderr198
20 files changed, 496 insertions, 66 deletions
diff --git a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
index c6a4ff6f0e0..357c6900a70 100644
--- a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
@@ -133,3 +133,7 @@ hir_analysis_extern_crate_not_idiomatic =
     .suggestion = convert it to a `{$msg_code}`
 
 hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
+
+hir_analysis_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
+
+hir_analysis_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
diff --git a/compiler/rustc_hir_analysis/src/check/method/suggest.rs b/compiler/rustc_hir_analysis/src/check/method/suggest.rs
index e276c4f7d84..bfa5b68168f 100644
--- a/compiler/rustc_hir_analysis/src/check/method/suggest.rs
+++ b/compiler/rustc_hir_analysis/src/check/method/suggest.rs
@@ -2,6 +2,7 @@
 //! found or is otherwise invalid.
 
 use crate::check::FnCtxt;
+use crate::errors;
 use rustc_ast::ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{
@@ -271,7 +272,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 };
 
-                if self.suggest_constraining_numerical_ty(
+                if self.suggest_wrapping_range_with_parens(
+                    tcx, actual, source, span, item_name, &ty_str,
+                ) || self.suggest_constraining_numerical_ty(
                     tcx, actual, source, span, item_kind, item_name, &ty_str,
                 ) {
                     return None;
@@ -1202,6 +1205,89 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         false
     }
 
+    /// Suggest possible range with adding parentheses, for example:
+    /// when encountering `0..1.map(|i| i + 1)` suggest `(0..1).map(|i| i + 1)`.
+    fn suggest_wrapping_range_with_parens(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        actual: Ty<'tcx>,
+        source: SelfSource<'tcx>,
+        span: Span,
+        item_name: Ident,
+        ty_str: &str,
+    ) -> bool {
+        if let SelfSource::MethodCall(expr) = source {
+            for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) {
+                if let Node::Expr(parent_expr) = parent {
+                    let lang_item = match parent_expr.kind {
+                        ExprKind::Struct(ref qpath, _, _) => match **qpath {
+                            QPath::LangItem(LangItem::Range, ..) => Some(LangItem::Range),
+                            QPath::LangItem(LangItem::RangeTo, ..) => Some(LangItem::RangeTo),
+                            QPath::LangItem(LangItem::RangeToInclusive, ..) => {
+                                Some(LangItem::RangeToInclusive)
+                            }
+                            _ => None,
+                        },
+                        ExprKind::Call(ref func, _) => match func.kind {
+                            // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
+                            ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, ..)) => {
+                                Some(LangItem::RangeInclusiveStruct)
+                            }
+                            _ => None,
+                        },
+                        _ => None,
+                    };
+
+                    if lang_item.is_none() {
+                        continue;
+                    }
+
+                    let span_included = match parent_expr.kind {
+                        hir::ExprKind::Struct(_, eps, _) => {
+                            eps.len() > 0 && eps.last().map_or(false, |ep| ep.span.contains(span))
+                        }
+                        // `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
+                        hir::ExprKind::Call(ref func, ..) => func.span.contains(span),
+                        _ => false,
+                    };
+
+                    if !span_included {
+                        continue;
+                    }
+
+                    let range_def_id = self.tcx.require_lang_item(lang_item.unwrap(), None);
+                    let range_ty =
+                        self.tcx.bound_type_of(range_def_id).subst(self.tcx, &[actual.into()]);
+
+                    let pick = self.probe_for_name(
+                        span,
+                        Mode::MethodCall,
+                        item_name,
+                        IsSuggestion(true),
+                        range_ty,
+                        expr.hir_id,
+                        ProbeScope::AllTraits,
+                    );
+                    if pick.is_ok() {
+                        let range_span = parent_expr.span.with_hi(expr.span.hi());
+                        tcx.sess.emit_err(errors::MissingParentheseInRange {
+                            span,
+                            ty_str: ty_str.to_string(),
+                            method_name: item_name.as_str().to_string(),
+                            add_missing_parentheses: Some(errors::AddMissingParenthesesInRange {
+                                func_name: item_name.name.as_str().to_string(),
+                                left: range_span.shrink_to_lo(),
+                                right: range_span.shrink_to_hi(),
+                            }),
+                        });
+                        return true;
+                    }
+                }
+            }
+        }
+        false
+    }
+
     fn suggest_constraining_numerical_ty(
         &self,
         tcx: TyCtxt<'tcx>,
@@ -1264,7 +1350,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // If this is a floating point literal that ends with '.',
                     // get rid of it to stop this from becoming a member access.
                     let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
-
                     err.span_suggestion(
                         lit.span,
                         &format!(
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index d891171b824..41f73323d9a 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -346,3 +346,29 @@ pub struct ExpectedUsedSymbol {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis::missing_parentheses_in_range, code = "E0689")]
+pub struct MissingParentheseInRange {
+    #[primary_span]
+    #[label(hir_analysis::missing_parentheses_in_range)]
+    pub span: Span,
+    pub ty_str: String,
+    pub method_name: String,
+
+    #[subdiagnostic]
+    pub add_missing_parentheses: Option<AddMissingParenthesesInRange>,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion_verbose(
+    hir_analysis::add_missing_parentheses_in_range,
+    applicability = "maybe-incorrect"
+)]
+pub struct AddMissingParenthesesInRange {
+    pub func_name: String,
+    #[suggestion_part(code = "(")]
+    pub left: Span,
+    #[suggestion_part(code = ")")]
+    pub right: Span,
+}
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 6eb02395685..d4c73427386 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -355,7 +355,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 }
 
                 ty::PredicateKind::RegionOutlives(data) => {
-                    if infcx.considering_regions || data.has_placeholders() {
+                    if infcx.considering_regions {
                         infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data));
                     }
 
@@ -492,19 +492,20 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 }
 
                 ty::PredicateKind::ConstEquate(c1, c2) => {
+                    assert!(
+                        self.selcx.tcx().features().generic_const_exprs,
+                        "`ConstEquate` without a feature gate: {c1:?} {c2:?}",
+                    );
                     debug!(?c1, ?c2, "equating consts");
-                    let tcx = self.selcx.tcx();
-                    if tcx.features().generic_const_exprs {
-                        // FIXME: we probably should only try to unify abstract constants
-                        // if the constants depend on generic parameters.
-                        //
-                        // Let's just see where this breaks :shrug:
-                        if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
-                            (c1.kind(), c2.kind())
-                        {
-                            if infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
-                                return ProcessResult::Changed(vec![]);
-                            }
+                    // FIXME: we probably should only try to unify abstract constants
+                    // if the constants depend on generic parameters.
+                    //
+                    // Let's just see where this breaks :shrug:
+                    if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
+                        (c1.kind(), c2.kind())
+                    {
+                        if infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
+                            return ProcessResult::Changed(vec![]);
                         }
                     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index ddabea700d3..9ebff489201 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -676,19 +676,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
 
                 ty::PredicateKind::ConstEquate(c1, c2) => {
+                    assert!(
+                        self.tcx().features().generic_const_exprs,
+                        "`ConstEquate` without a feature gate: {c1:?} {c2:?}",
+                    );
                     debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts");
 
-                    if self.tcx().features().generic_const_exprs {
-                        // FIXME: we probably should only try to unify abstract constants
-                        // if the constants depend on generic parameters.
-                        //
-                        // Let's just see where this breaks :shrug:
-                        if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
-                            (c1.kind(), c2.kind())
-                        {
-                            if self.infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
-                                return Ok(EvaluatedToOk);
-                            }
+                    // FIXME: we probably should only try to unify abstract constants
+                    // if the constants depend on generic parameters.
+                    //
+                    // Let's just see where this breaks :shrug:
+                    if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
+                        (c1.kind(), c2.kind())
+                    {
+                        if self.infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
+                            return Ok(EvaluatedToOk);
                         }
                     }
 
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 1e162bf314b..cd56d73e7d4 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -2259,13 +2259,7 @@ fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String
 }
 
 fn print_sidebar_title(buf: &mut Buffer, id: &str, title: &str) {
-    write!(
-        buf,
-        "<h3 class=\"sidebar-title\">\
-             <a href=\"#{}\">{}</a>\
-         </h3>",
-        id, title
-    );
+    write!(buf, "<h3><a href=\"#{}\">{}</a></h3>", id, title);
 }
 
 fn print_sidebar_block(
diff --git a/src/test/rustdoc-gui/sidebar-mobile.goml b/src/test/rustdoc-gui/sidebar-mobile.goml
index 4cded2c773d..4b3ec79273d 100644
--- a/src/test/rustdoc-gui/sidebar-mobile.goml
+++ b/src/test/rustdoc-gui/sidebar-mobile.goml
@@ -13,7 +13,7 @@ click: ".sidebar-menu-toggle"
 assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
 // Force the sidebar open by focusing a link inside it.
 // This makes it easier for keyboard users to get to it.
-focus: ".sidebar-title a"
+focus: ".sidebar-elems h3 a"
 assert-css: (".sidebar", {"display": "block", "left": "0px"})
 // When we tab out of the sidebar, close it.
 focus: ".search-input"
diff --git a/src/test/rustdoc/associated-consts.rs b/src/test/rustdoc/associated-consts.rs
index 9319a073bb7..adb155bb525 100644
--- a/src/test/rustdoc/associated-consts.rs
+++ b/src/test/rustdoc/associated-consts.rs
@@ -9,7 +9,7 @@ pub trait Trait {
 pub struct Bar;
 
 // @has 'foo/struct.Bar.html'
-// @!has - '//h3[@class="sidebar-title"]' 'Associated Constants'
+// @!has - '//div[@class="sidebar-elems"]//h3' 'Associated Constants'
 // @!has - '//div[@class="sidebar-elems"]//a' 'FOO'
 impl Trait for Bar {
     const FOO: u32 = 1;
@@ -22,7 +22,7 @@ pub enum Foo {
 }
 
 // @has 'foo/enum.Foo.html'
-// @!has - '//h3[@class="sidebar-title"]' 'Associated Constants'
+// @!has - '//div[@class="sidebar-elems"]//h3' 'Associated Constants'
 // @!has - '//div[@class="sidebar-elems"]//a' 'FOO'
 impl Trait for Foo {
     const FOO: u32 = 1;
@@ -33,7 +33,7 @@ impl Trait for Foo {
 pub struct Baz;
 
 // @has 'foo/struct.Baz.html'
-// @has - '//h3[@class="sidebar-title"]' 'Associated Constants'
+// @has - '//div[@class="sidebar-elems"]//h3' 'Associated Constants'
 // @has - '//div[@class="sidebar-elems"]//a' 'FOO'
 impl Baz {
     pub const FOO: u32 = 42;
@@ -44,7 +44,7 @@ pub enum Quux {
 }
 
 // @has 'foo/enum.Quux.html'
-// @has - '//h3[@class="sidebar-title"]' 'Associated Constants'
+// @has - '//div[@class="sidebar-elems"]//h3' 'Associated Constants'
 // @has - '//div[@class="sidebar-elems"]//a' 'FOO'
 impl Quux {
     pub const FOO: u32 = 42;
diff --git a/src/test/rustdoc/deref-recursive-pathbuf.rs b/src/test/rustdoc/deref-recursive-pathbuf.rs
index 746df9c804e..be2b42b5ac6 100644
--- a/src/test/rustdoc/deref-recursive-pathbuf.rs
+++ b/src/test/rustdoc/deref-recursive-pathbuf.rs
@@ -7,9 +7,9 @@
 // @has '-' '//*[@class="impl-items"]//*[@id="method.as_path"]' 'pub fn as_path(&self)'
 // @has '-' '//*[@id="deref-methods-Path"]' 'Methods from Deref<Target = Path>'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.exists"]' 'pub fn exists(&self)'
-// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>'
+// @has '-' '//div[@class="sidebar-elems"]//h3/a[@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>'
 // @has '-' '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.as_path"]' 'as_path'
-// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>'
+// @has '-' '//div[@class="sidebar-elems"]//h3/a[@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>'
 // @has '-' '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.exists"]' 'exists'
 
 #![crate_name = "foo"]
diff --git a/src/test/rustdoc/deref-recursive.rs b/src/test/rustdoc/deref-recursive.rs
index d5f8473f284..0436f2f86f5 100644
--- a/src/test/rustdoc/deref-recursive.rs
+++ b/src/test/rustdoc/deref-recursive.rs
@@ -7,9 +7,9 @@
 // @has '-' '//*[@class="impl-items"]//*[@id="method.bar"]' 'pub fn bar(&self)'
 // @has '-' '//*[@id="deref-methods-Baz"]' 'Methods from Deref<Target = Baz>'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.baz"]' 'pub fn baz(&self)'
-// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>'
+// @has '-' '//div[@class="sidebar-elems"]//h3/a[@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>'
 // @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.bar"]' 'bar'
-// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Baz"]' 'Methods from Deref<Target=Baz>'
+// @has '-' '//div[@class="sidebar-elems"]//h3/a[@href="#deref-methods-Baz"]' 'Methods from Deref<Target=Baz>'
 // @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.baz"]' 'baz'
 
 #![crate_name = "foo"]
diff --git a/src/test/rustdoc/deref-typedef.rs b/src/test/rustdoc/deref-typedef.rs
index 28f977e315a..32424d13eb8 100644
--- a/src/test/rustdoc/deref-typedef.rs
+++ b/src/test/rustdoc/deref-typedef.rs
@@ -6,7 +6,7 @@
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_b"]' 'pub fn foo_b(&self)'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)'
-// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>'
+// @has '-' '//div[@class="sidebar-elems"]//h3/a[@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>'
 // @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_a"]' 'foo_a'
 // @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_b"]' 'foo_b'
 // @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_c"]' 'foo_c'
diff --git a/src/test/rustdoc/escape-deref-methods.rs b/src/test/rustdoc/escape-deref-methods.rs
index a62ad2c4001..66919d73eeb 100644
--- a/src/test/rustdoc/escape-deref-methods.rs
+++ b/src/test/rustdoc/escape-deref-methods.rs
@@ -27,7 +27,7 @@ impl Deref for TitleList {
 }
 
 // @has foo/struct.TitleList.html
-// @has - '//*[@class="sidebar-title"]' 'Methods from Deref<Target=Vec<Title>>'
+// @has - '//div[@class="sidebar-elems"]//h3' 'Methods from Deref<Target=Vec<Title>>'
 impl DerefMut for TitleList {
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.members
diff --git a/src/test/rustdoc/negative-impl-sidebar.rs b/src/test/rustdoc/negative-impl-sidebar.rs
index b995fff1f9a..4af6d008492 100644
--- a/src/test/rustdoc/negative-impl-sidebar.rs
+++ b/src/test/rustdoc/negative-impl-sidebar.rs
@@ -4,6 +4,6 @@
 pub struct Foo;
 
 // @has foo/struct.Foo.html
-// @has - '//*[@class="sidebar-title"]/a[@href="#trait-implementations"]' 'Trait Implementations'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#trait-implementations"]' 'Trait Implementations'
 // @has - '//*[@class="sidebar-elems"]//section//a' '!Sync'
 impl !Sync for Foo {}
diff --git a/src/test/rustdoc/sidebar-items.rs b/src/test/rustdoc/sidebar-items.rs
index b5b681ab085..6f7afa59bdd 100644
--- a/src/test/rustdoc/sidebar-items.rs
+++ b/src/test/rustdoc/sidebar-items.rs
@@ -2,17 +2,17 @@
 #![crate_name = "foo"]
 
 // @has foo/trait.Foo.html
-// @has - '//*[@class="sidebar-title"]/a[@href="#required-methods"]' 'Required Methods'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#required-methods"]' 'Required Methods'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'bar'
-// @has - '//*[@class="sidebar-title"]/a[@href="#provided-methods"]' 'Provided Methods'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#provided-methods"]' 'Provided Methods'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'foo'
-// @has - '//*[@class="sidebar-title"]/a[@href="#required-associated-consts"]' 'Required Associated Constants'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#required-associated-consts"]' 'Required Associated Constants'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'FOO'
-// @has - '//*[@class="sidebar-title"]/a[@href="#provided-associated-consts"]' 'Provided Associated Constants'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#provided-associated-consts"]' 'Provided Associated Constants'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'BAR'
-// @has - '//*[@class="sidebar-title"]/a[@href="#required-associated-types"]' 'Required Associated Types'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#required-associated-types"]' 'Required Associated Types'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'Output'
-// @has - '//*[@class="sidebar-title"]/a[@href="#provided-associated-types"]' 'Provided Associated Types'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#provided-associated-types"]' 'Provided Associated Types'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'Extra'
 pub trait Foo {
     const FOO: usize;
@@ -25,7 +25,7 @@ pub trait Foo {
 }
 
 // @has foo/struct.Bar.html
-// @has - '//*[@class="sidebar-title"]/a[@href="#fields"]' 'Fields'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#fields"]' 'Fields'
 // @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f"]' 'f'
 // @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.u"]' 'u'
 // @!has - '//*[@class="sidebar-elems"]//section//a' 'waza'
@@ -36,7 +36,7 @@ pub struct Bar {
 }
 
 // @has foo/enum.En.html
-// @has - '//*[@class="sidebar-title"]/a[@href="#variants"]' 'Variants'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#variants"]' 'Variants'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'Foo'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'Bar'
 pub enum En {
@@ -45,7 +45,7 @@ pub enum En {
 }
 
 // @has foo/union.MyUnion.html
-// @has - '//*[@class="sidebar-title"]/a[@href="#fields"]' 'Fields'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#fields"]' 'Fields'
 // @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f1"]' 'f1'
 // @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f2"]' 'f2'
 // @!has - '//*[@class="sidebar-elems"]//section//a' 'waza'
diff --git a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
index 6712af527a3..11e94694802 100644
--- a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
+++ b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
@@ -3,7 +3,7 @@
 #![crate_name = "foo"]
 
 // @has foo/trait.Foo.html
-// @has - '//*[@class="sidebar-title"]/a[@href="#foreign-impls"]' 'Implementations on Foreign Types'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#foreign-impls"]' 'Implementations on Foreign Types'
 // @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types'
 // @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-u32"]' 'u32'
 // @has - '//*[@id="impl-Foo-for-u32"]//h3[@class="code-header"]' 'impl Foo for u32'
diff --git a/src/test/rustdoc/tuple-struct-fields-doc.rs b/src/test/rustdoc/tuple-struct-fields-doc.rs
index 66bb409325c..8ab1143d1f7 100644
--- a/src/test/rustdoc/tuple-struct-fields-doc.rs
+++ b/src/test/rustdoc/tuple-struct-fields-doc.rs
@@ -2,7 +2,7 @@
 
 // @has foo/struct.Foo.html
 // @has - '//h2[@id="fields"]' 'Tuple Fields'
-// @has - '//h3[@class="sidebar-title"]/a[@href="#fields"]' 'Tuple Fields'
+// @has - '//div[@class="sidebar-elems"]//h3/a[@href="#fields"]' 'Tuple Fields'
 // @has - '//*[@id="structfield.0"]' '0: u32'
 // @has - '//*[@id="main-content"]/div[@class="docblock"]' 'hello'
 // @!has - '//*[@id="structfield.1"]' ''
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-100689.rs b/src/test/ui/higher-rank-trait-bounds/issue-100689.rs
new file mode 100644
index 00000000000..2db7f8a354c
--- /dev/null
+++ b/src/test/ui/higher-rank-trait-bounds/issue-100689.rs
@@ -0,0 +1,29 @@
+// check-pass
+
+struct Foo<'a> {
+    foo: &'a mut usize,
+}
+
+trait Bar<'a> {
+    type FooRef<'b>
+    where
+        'a: 'b;
+    fn uwu(foo: Foo<'a>, f: impl for<'b> FnMut(Self::FooRef<'b>));
+}
+impl<'a> Bar<'a> for () {
+    type FooRef<'b>
+    =
+        &'b Foo<'a>
+    where
+        'a : 'b,
+    ;
+
+    fn uwu(
+        foo: Foo<'a>,
+        mut f: impl for<'b> FnMut(&'b Foo<'a>), //relevant part
+    ) {
+        f(&foo);
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-102899.rs b/src/test/ui/higher-rank-trait-bounds/issue-102899.rs
new file mode 100644
index 00000000000..952b81584f3
--- /dev/null
+++ b/src/test/ui/higher-rank-trait-bounds/issue-102899.rs
@@ -0,0 +1,32 @@
+// check-pass
+
+pub trait BufferTrait<'buffer> {
+    type Subset<'channel>
+    where
+        'buffer: 'channel;
+
+    fn for_each_subset<F>(&self, f: F)
+    where
+        F: for<'channel> Fn(Self::Subset<'channel>);
+}
+
+pub struct SomeBuffer<'buffer> {
+    samples: &'buffer [()],
+}
+
+impl<'buffer> BufferTrait<'buffer> for SomeBuffer<'buffer> {
+    type Subset<'subset> = Subset<'subset> where 'buffer: 'subset;
+
+    fn for_each_subset<F>(&self, _f: F)
+    where
+        F: for<'subset> Fn(Subset<'subset>),
+    {
+        todo!()
+    }
+}
+
+pub struct Subset<'subset> {
+    buffer: &'subset [()],
+}
+
+fn main() {}
diff --git a/src/test/ui/methods/issues/issue-90315.rs b/src/test/ui/methods/issues/issue-90315.rs
index 01bf9f48402..79cdc41959a 100644
--- a/src/test/ui/methods/issues/issue-90315.rs
+++ b/src/test/ui/methods/issues/issue-90315.rs
@@ -1,7 +1,76 @@
+#![allow(unused)]
 fn main() {
-  let arr = &[0,1,2,3];
-  for _i in 0..arr.len().rev() { //~ERROR not an iterator
-     // The above error used to say “the method `rev` exists for type `usize`”.
-     // This regression test ensures it doesn't say that any more.
-  }
+    let arr = &[0, 1, 2, 3];
+    for _i in 0..arr.len().rev() {
+        //~^ ERROR can't call method
+        //~| surround the range in parentheses
+        // The above error used to say “the method `rev` exists for type `usize`”.
+        // This regression test ensures it doesn't say that any more.
+    }
+
+    // Test for #102396
+    for i in 1..11.rev() {
+        //~^ ERROR can't call method
+        //~| HELP surround the range in parentheses
+    }
+
+    let end: usize = 10;
+    for i in 1..end.rev() {
+        //~^ ERROR can't call method
+        //~| HELP surround the range in parentheses
+    }
+
+    for i in 1..(end + 1).rev() {
+        //~^ ERROR can't call method
+        //~| HELP surround the range in parentheses
+    }
+
+    if 1..(end + 1).is_empty() {
+        //~^ ERROR can't call method
+        //~| ERROR mismatched types [E0308]
+        //~| HELP surround the range in parentheses
+    }
+
+    if 1..(end + 1).is_sorted() {
+        //~^ ERROR mismatched types [E0308]
+        //~| ERROR can't call method
+        //~| HELP surround the range in parentheses
+    }
+
+    let _res: i32 = 3..6.take(2).sum();
+    //~^ ERROR can't call method
+    //~| ERROR mismatched types [E0308]
+    //~| HELP surround the range in parentheses
+
+    let _sum: i32 = 3..6.sum();
+    //~^ ERROR can't call method
+    //~| ERROR mismatched types [E0308]
+    //~| HELP surround the range in parentheses
+
+    let a = 1 as usize;
+    let b = 10 as usize;
+
+    for _a in a..=b.rev() {
+        //~^ ERROR can't call method
+        //~| HELP surround the range in parentheses
+    }
+
+    let _res = ..10.contains(3);
+    //~^ ERROR can't call method
+    //~| HELP surround the range in parentheses
+
+    if 1..end.error_method() {
+        //~^ ERROR no method named `error_method`
+        //~| ERROR mismatched types [E0308]
+        // Won't suggest
+    }
+
+    let _res = b.take(1)..a;
+    //~^ ERROR `usize` is not an iterator
+
+    let _res: i32 = ..6.take(2).sum();
+    //~^ can't call method `take` on ambiguous numeric type
+    //~| ERROR mismatched types [E0308]
+    //~| HELP you must specify a concrete type for this numeric value
+    // Won't suggest because `RangeTo` dest not implemented `take`
 }
diff --git a/src/test/ui/methods/issues/issue-90315.stderr b/src/test/ui/methods/issues/issue-90315.stderr
index c6a76c9e790..070cd305436 100644
--- a/src/test/ui/methods/issues/issue-90315.stderr
+++ b/src/test/ui/methods/issues/issue-90315.stderr
@@ -1,13 +1,201 @@
+error[E0689]: can't call method `rev` on type `usize`
+  --> $DIR/issue-90315.rs:4:28
+   |
+LL |     for _i in 0..arr.len().rev() {
+   |                            ^^^ can't call method `rev` on type `usize`
+   |
+help: you must surround the range in parentheses to call its `rev` function
+   |
+LL |     for _i in (0..arr.len()).rev() {
+   |               +            +
+
+error[E0689]: can't call method `rev` on type `{integer}`
+  --> $DIR/issue-90315.rs:12:20
+   |
+LL |     for i in 1..11.rev() {
+   |                    ^^^ can't call method `rev` on type `{integer}`
+   |
+help: you must surround the range in parentheses to call its `rev` function
+   |
+LL |     for i in (1..11).rev() {
+   |              +     +
+
+error[E0689]: can't call method `rev` on type `usize`
+  --> $DIR/issue-90315.rs:18:21
+   |
+LL |     for i in 1..end.rev() {
+   |                     ^^^ can't call method `rev` on type `usize`
+   |
+help: you must surround the range in parentheses to call its `rev` function
+   |
+LL |     for i in (1..end).rev() {
+   |              +      +
+
+error[E0689]: can't call method `rev` on type `usize`
+  --> $DIR/issue-90315.rs:23:27
+   |
+LL |     for i in 1..(end + 1).rev() {
+   |                           ^^^ can't call method `rev` on type `usize`
+   |
+help: you must surround the range in parentheses to call its `rev` function
+   |
+LL |     for i in (1..(end + 1)).rev() {
+   |              +            +
+
+error[E0689]: can't call method `is_empty` on type `usize`
+  --> $DIR/issue-90315.rs:28:21
+   |
+LL |     if 1..(end + 1).is_empty() {
+   |                     ^^^^^^^^ can't call method `is_empty` on type `usize`
+   |
+help: you must surround the range in parentheses to call its `is_empty` function
+   |
+LL |     if (1..(end + 1)).is_empty() {
+   |        +            +
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90315.rs:28:8
+   |
+LL |     if 1..(end + 1).is_empty() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |
+   = note: expected type `bool`
+            found struct `std::ops::Range<{integer}>`
+
+error[E0689]: can't call method `is_sorted` on type `usize`
+  --> $DIR/issue-90315.rs:34:21
+   |
+LL |     if 1..(end + 1).is_sorted() {
+   |                     ^^^^^^^^^ can't call method `is_sorted` on type `usize`
+   |
+help: you must surround the range in parentheses to call its `is_sorted` function
+   |
+LL |     if (1..(end + 1)).is_sorted() {
+   |        +            +
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90315.rs:34:8
+   |
+LL |     if 1..(end + 1).is_sorted() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |
+   = note: expected type `bool`
+            found struct `std::ops::Range<{integer}>`
+
+error[E0689]: can't call method `take` on type `{integer}`
+  --> $DIR/issue-90315.rs:40:26
+   |
+LL |     let _res: i32 = 3..6.take(2).sum();
+   |                          ^^^^ can't call method `take` on type `{integer}`
+   |
+help: you must surround the range in parentheses to call its `take` function
+   |
+LL |     let _res: i32 = (3..6).take(2).sum();
+   |                     +    +
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90315.rs:40:21
+   |
+LL |     let _res: i32 = 3..6.take(2).sum();
+   |               ---   ^^^^^^^^^^^^^^^^^^ expected `i32`, found struct `std::ops::Range`
+   |               |
+   |               expected due to this
+   |
+   = note: expected type `i32`
+            found struct `std::ops::Range<{integer}>`
+
+error[E0689]: can't call method `sum` on type `{integer}`
+  --> $DIR/issue-90315.rs:45:26
+   |
+LL |     let _sum: i32 = 3..6.sum();
+   |                          ^^^ can't call method `sum` on type `{integer}`
+   |
+help: you must surround the range in parentheses to call its `sum` function
+   |
+LL |     let _sum: i32 = (3..6).sum();
+   |                     +    +
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90315.rs:45:21
+   |
+LL |     let _sum: i32 = 3..6.sum();
+   |               ---   ^^^^^^^^^^ expected `i32`, found struct `std::ops::Range`
+   |               |
+   |               expected due to this
+   |
+   = note: expected type `i32`
+            found struct `std::ops::Range<{integer}>`
+
+error[E0689]: can't call method `rev` on type `usize`
+  --> $DIR/issue-90315.rs:53:21
+   |
+LL |     for _a in a..=b.rev() {
+   |                     ^^^ can't call method `rev` on type `usize`
+   |
+help: you must surround the range in parentheses to call its `rev` function
+   |
+LL |     for _a in (a..=b).rev() {
+   |               +     +
+
+error[E0689]: can't call method `contains` on type `{integer}`
+  --> $DIR/issue-90315.rs:58:21
+   |
+LL |     let _res = ..10.contains(3);
+   |                     ^^^^^^^^ can't call method `contains` on type `{integer}`
+   |
+help: you must surround the range in parentheses to call its `contains` function
+   |
+LL |     let _res = (..10).contains(3);
+   |                +    +
+
+error[E0599]: no method named `error_method` found for type `usize` in the current scope
+  --> $DIR/issue-90315.rs:62:15
+   |
+LL |     if 1..end.error_method() {
+   |               ^^^^^^^^^^^^ method not found in `usize`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90315.rs:62:8
+   |
+LL |     if 1..end.error_method() {
+   |        ^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
+   |
+   = note: expected type `bool`
+            found struct `std::ops::Range<{integer}>`
+
 error[E0599]: `usize` is not an iterator
-  --> $DIR/issue-90315.rs:3:26
+  --> $DIR/issue-90315.rs:68:18
    |
-LL |   for _i in 0..arr.len().rev() {
-   |                          ^^^ `usize` is not an iterator
+LL |     let _res = b.take(1)..a;
+   |                  ^^^^ `usize` is not an iterator
    |
    = note: the following trait bounds were not satisfied:
            `usize: Iterator`
            which is required by `&mut usize: Iterator`
 
-error: aborting due to previous error
+error[E0689]: can't call method `take` on ambiguous numeric type `{integer}`
+  --> $DIR/issue-90315.rs:71:25
+   |
+LL |     let _res: i32 = ..6.take(2).sum();
+   |                         ^^^^
+   |
+help: you must specify a concrete type for this numeric value, like `i32`
+   |
+LL |     let _res: i32 = ..6_i32.take(2).sum();
+   |                       ~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90315.rs:71:21
+   |
+LL |     let _res: i32 = ..6.take(2).sum();
+   |               ---   ^^^^^^^^^^^^^^^^^ expected `i32`, found struct `RangeTo`
+   |               |
+   |               expected due to this
+   |
+   = note: expected type `i32`
+            found struct `RangeTo<_>`
+
+error: aborting due to 19 previous errors
 
-For more information about this error, try `rustc --explain E0599`.
+Some errors have detailed explanations: E0308, E0599, E0689.
+For more information about an error, try `rustc --explain E0308`.