about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-12-29 12:07:33 +0000
committerbors <bors@rust-lang.org>2021-12-29 12:07:33 +0000
commit2b67c30bfece00357d5fc09d99b49f21066f04ba (patch)
treead36e3e5492f2cd163e10b47db2b0bc3359ef337
parent6211dd7250e9b8e80733f74911ca88c661adb1a9 (diff)
parent949769cf3bb3f81293fbdaaac64d38bd97942158 (diff)
downloadrust-2b67c30bfece00357d5fc09d99b49f21066f04ba.tar.gz
rust-2b67c30bfece00357d5fc09d99b49f21066f04ba.zip
Auto merge of #92397 - matthiaskrgr:rollup-xnfou17, r=matthiaskrgr
Rollup of 7 pull requests

Successful merges:

 - #92075 (rustdoc: Only special case struct fields for intra-doc links, not enum variants)
 - #92118 (Parse and suggest moving where clauses after equals for type aliases)
 - #92237 (Visit expressions in-order when resolving pattern bindings)
 - #92340 (rustdoc: Start cleaning up search index generation)
 - #92351 (Add long error explanation for E0227)
 - #92371 (Remove pretty printer space inside block with only outer attrs)
 - #92372 (Print space after formal generic params in fn type)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs84
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0227.md33
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs5
-rw-r--r--compiler/rustc_parse/src/parser/item.rs53
-rw-r--r--compiler/rustc_resolve/src/late.rs5
-rw-r--r--src/librustdoc/clean/types.rs11
-rw-r--r--src/librustdoc/formats/cache.rs6
-rw-r--r--src/librustdoc/html/format.rs6
-rw-r--r--src/librustdoc/html/render/context.rs4
-rw-r--r--src/librustdoc/html/render/mod.rs2
-rw-r--r--src/librustdoc/html/render/search_index.rs (renamed from src/librustdoc/html/render/cache.rs)72
-rw-r--r--src/librustdoc/json/mod.rs3
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs41
-rw-r--r--src/test/pretty/attr-fn-inner.rs4
-rw-r--r--src/test/pretty/attr-literals.rs4
-rw-r--r--src/test/pretty/attr-tokens-raw-ident.rs2
-rw-r--r--src/test/pretty/delimited-token-groups.rs2
-rw-r--r--src/test/pretty/doc-comments.rs10
-rw-r--r--src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs11
-rw-r--r--src/test/ui/error-codes/E0227.rs12
-rw-r--r--src/test/ui/error-codes/E0227.stderr9
-rw-r--r--src/test/ui/macros/stringify.rs4
-rw-r--r--src/test/ui/match/expr_before_ident_pat.rs15
-rw-r--r--src/test/ui/match/expr_before_ident_pat.stderr15
-rw-r--r--src/test/ui/match/issue-92100.rs7
-rw-r--r--src/test/ui/match/issue-92100.stderr9
-rw-r--r--src/test/ui/parser/type-alias-where.rs37
-rw-r--r--src/test/ui/parser/type-alias-where.stderr40
-rw-r--r--src/tools/tidy/src/error_codes_check.rs4
30 files changed, 382 insertions, 130 deletions
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 6c5b38bc4bb..f0c1d017326 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -387,23 +387,23 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
         self.print_string(sym.as_str(), style);
     }
 
-    fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) {
+    fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) -> bool {
         self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
     }
 
-    fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) {
+    fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) -> bool {
         self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false)
     }
 
-    fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) {
+    fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) -> bool {
         self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
     }
 
-    fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) {
+    fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool {
         self.print_either_attributes(attrs, ast::AttrStyle::Inner, true, true)
     }
 
-    fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) {
+    fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool {
         self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true)
     }
 
@@ -413,20 +413,21 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
         kind: ast::AttrStyle,
         is_inline: bool,
         trailing_hardbreak: bool,
-    ) {
-        let mut count = 0;
+    ) -> bool {
+        let mut printed = false;
         for attr in attrs {
             if attr.style == kind {
                 self.print_attribute_inline(attr, is_inline);
                 if is_inline {
                     self.nbsp();
                 }
-                count += 1;
+                printed = true;
             }
         }
-        if count > 0 && trailing_hardbreak && !is_inline {
+        if printed && trailing_hardbreak && !is_inline {
             self.hardbreak_if_not_bol();
         }
+        printed
     }
 
     fn print_attribute(&mut self, attr: &ast::Attribute) {
@@ -1646,7 +1647,7 @@ impl<'a> State<'a> {
         self.ann.pre(self, AnnNode::Block(blk));
         self.bopen();
 
-        self.print_inner_attributes(attrs);
+        let has_attrs = self.print_inner_attributes(attrs);
 
         for (i, st) in blk.stmts.iter().enumerate() {
             match st.kind {
@@ -1660,7 +1661,7 @@ impl<'a> State<'a> {
             }
         }
 
-        let empty = attrs.is_empty() && blk.stmts.is_empty();
+        let empty = !has_attrs && blk.stmts.is_empty();
         self.bclose_maybe_open(blk.span, empty, close_box);
         self.ann.post(self, AnnNode::Block(blk))
     }
@@ -2780,34 +2781,34 @@ impl<'a> State<'a> {
                 self.word_space(",");
             }
 
-            match *predicate {
-                ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
-                    ref bound_generic_params,
-                    ref bounded_ty,
-                    ref bounds,
-                    ..
-                }) => {
-                    self.print_formal_generic_params(bound_generic_params);
-                    self.print_type(bounded_ty);
-                    self.print_type_bounds(":", bounds);
-                }
-                ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
-                    ref lifetime,
-                    ref bounds,
-                    ..
-                }) => {
-                    self.print_lifetime_bounds(*lifetime, bounds);
-                }
-                ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
-                    ref lhs_ty,
-                    ref rhs_ty,
-                    ..
-                }) => {
-                    self.print_type(lhs_ty);
-                    self.space();
-                    self.word_space("=");
-                    self.print_type(rhs_ty);
-                }
+            self.print_where_predicate(predicate);
+        }
+    }
+
+    pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
+        match predicate {
+            ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
+                bound_generic_params,
+                bounded_ty,
+                bounds,
+                ..
+            }) => {
+                self.print_formal_generic_params(bound_generic_params);
+                self.print_type(bounded_ty);
+                self.print_type_bounds(":", bounds);
+            }
+            ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
+                lifetime,
+                bounds,
+                ..
+            }) => {
+                self.print_lifetime_bounds(*lifetime, bounds);
+            }
+            ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
+                self.print_type(lhs_ty);
+                self.space();
+                self.word_space("=");
+                self.print_type(rhs_ty);
             }
         }
     }
@@ -2908,10 +2909,7 @@ impl<'a> State<'a> {
         generic_params: &[ast::GenericParam],
     ) {
         self.ibox(INDENT_UNIT);
-        if !generic_params.is_empty() {
-            self.word("for");
-            self.print_generic_params(generic_params);
-        }
+        self.print_formal_generic_params(generic_params);
         let generics = ast::Generics {
             params: Vec::new(),
             where_clause: ast::WhereClause {
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index ce26ff62235..79d9c55b547 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -120,6 +120,7 @@ E0223: include_str!("./error_codes/E0223.md"),
 E0224: include_str!("./error_codes/E0224.md"),
 E0225: include_str!("./error_codes/E0225.md"),
 E0226: include_str!("./error_codes/E0226.md"),
+E0227: include_str!("./error_codes/E0227.md"),
 E0228: include_str!("./error_codes/E0228.md"),
 E0229: include_str!("./error_codes/E0229.md"),
 E0230: include_str!("./error_codes/E0230.md"),
@@ -530,7 +531,6 @@ E0786: include_str!("./error_codes/E0786.md"),
 //  E0217, // ambiguous associated type, defined in multiple supertraits
 //  E0218, // no associated type defined
 //  E0219, // associated type defined in higher-ranked supertrait
-    E0227, // ambiguous lifetime bound, explicit lifetime bound required
 //  E0233,
 //  E0234,
 //  E0235, // structure constructor specifies a structure of type but
diff --git a/compiler/rustc_error_codes/src/error_codes/E0227.md b/compiler/rustc_error_codes/src/error_codes/E0227.md
new file mode 100644
index 00000000000..f68614723d4
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0227.md
@@ -0,0 +1,33 @@
+This error indicates that the compiler is unable to determine whether there is
+exactly one unique region in the set of derived region bounds.
+
+Example of erroneous code:
+
+```compile_fail,E0227
+trait Foo<'foo>: 'foo {}
+trait Bar<'bar>: 'bar {}
+
+trait FooBar<'foo, 'bar>: Foo<'foo> + Bar<'bar> {}
+
+struct Baz<'foo, 'bar> {
+    baz: dyn FooBar<'foo, 'bar>,
+}
+```
+
+Here, `baz` can have either `'foo` or `'bar` lifetimes.
+
+To resolve this error, provide an explicit lifetime:
+
+```rust
+trait Foo<'foo>: 'foo {}
+trait Bar<'bar>: 'bar {}
+
+trait FooBar<'foo, 'bar>: Foo<'foo> + Bar<'bar> {}
+
+struct Baz<'foo, 'bar, 'baz>
+where
+    'baz: 'foo + 'bar,
+{
+    obj: dyn FooBar<'foo, 'bar> + 'baz,
+}
+```
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 2f5f158856f..334fa6f4e5c 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -2327,10 +2327,7 @@ impl<'a> State<'a> {
         arg_names: &[Ident],
     ) {
         self.ibox(INDENT_UNIT);
-        if !generic_params.is_empty() {
-            self.word("for");
-            self.print_generic_params(generic_params);
-        }
+        self.print_formal_generic_params(generic_params);
         let generics = hir::Generics {
             params: &[],
             where_clause: hir::WhereClause { predicates: &[], span: rustc_span::DUMMY_SP },
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 618aa3fd002..d335ef8788b 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -794,6 +794,44 @@ impl<'a> Parser<'a> {
         ))
     }
 
+    /// Emits an error that the where clause at the end of a type alias is not
+    /// allowed and suggests moving it.
+    fn error_ty_alias_where(
+        &self,
+        before_where_clause_present: bool,
+        before_where_clause_span: Span,
+        after_predicates: &[WherePredicate],
+        after_where_clause_span: Span,
+    ) {
+        let mut err =
+            self.struct_span_err(after_where_clause_span, "where clause not allowed here");
+        if !after_predicates.is_empty() {
+            let mut state = crate::pprust::State::new();
+            if !before_where_clause_present {
+                state.space();
+                state.word_space("where");
+            } else {
+                state.word_space(",");
+            }
+            let mut first = true;
+            for p in after_predicates.iter() {
+                if !first {
+                    state.word_space(",");
+                }
+                first = false;
+                state.print_where_predicate(p);
+            }
+            let suggestion = state.s.eof();
+            err.span_suggestion(
+                before_where_clause_span.shrink_to_hi(),
+                "move it here",
+                suggestion,
+                Applicability::MachineApplicable,
+            );
+        }
+        err.emit()
+    }
+
     /// Parses a `type` alias with the following grammar:
     /// ```
     /// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ;
@@ -806,9 +844,24 @@ impl<'a> Parser<'a> {
         // Parse optional colon and param bounds.
         let bounds =
             if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() };
+
         generics.where_clause = self.parse_where_clause()?;
 
         let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
+
+        if self.token.is_keyword(kw::Where) {
+            let after_where_clause = self.parse_where_clause()?;
+
+            self.error_ty_alias_where(
+                generics.where_clause.has_where_token,
+                generics.where_clause.span,
+                &after_where_clause.predicates,
+                after_where_clause.span,
+            );
+
+            generics.where_clause.predicates.extend(after_where_clause.predicates.into_iter());
+        }
+
         self.expect_semi()?;
 
         Ok((ident, ItemKind::TyAlias(Box::new(TyAlias { defaultness, generics, bounds, ty }))))
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 12123c946cc..5098cef11e8 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1603,10 +1603,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         pat_src: PatternSource,
         bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet<Ident>); 1]>,
     ) {
+        // We walk the pattern before declaring the pattern's inner bindings,
+        // so that we avoid resolving a literal expression to a binding defined
+        // by the pattern.
+        visit::walk_pat(self, pat);
         self.resolve_pattern_inner(pat, pat_src, bindings);
         // This has to happen *after* we determine which pat_idents are variants:
         self.check_consistent_bindings_top(pat);
-        visit::walk_pat(self, pat);
     }
 
     /// Resolve bindings in a pattern. This is a helper to `resolve_pattern`.
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index d928b41cad4..2b1a1d4a600 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -39,7 +39,6 @@ use crate::clean::Clean;
 use crate::core::DocContext;
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
-use crate::html::render::cache::ExternalLocation;
 use crate::html::render::Context;
 use crate::passes::collect_intra_doc_links::UrlFragment;
 
@@ -339,6 +338,16 @@ impl ExternalCrate {
     }
 }
 
+/// Indicates where an external crate can be found.
+crate enum ExternalLocation {
+    /// Remote URL root of the external crate
+    Remote(String),
+    /// This external crate can be found in the local doc/ folder
+    Local,
+    /// The external crate could not be found.
+    Unknown,
+}
+
 /// Anything with a source location and set of attributes and, optionally, a
 /// name. That is, anything that can be documented. This doesn't correspond
 /// directly to the AST's concept of an item; it's a strict superset.
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 5813062ceab..6b9ccd37cfb 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -6,13 +6,13 @@ use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::sym;
 
-use crate::clean::{self, ExternalCrate, ItemId, PrimitiveType};
+use crate::clean::{self, types::ExternalLocation, ExternalCrate, ItemId, PrimitiveType};
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::formats::item_type::ItemType;
 use crate::formats::Impl;
 use crate::html::markdown::short_markdown_summary;
-use crate::html::render::cache::{get_index_search_type, ExternalLocation};
+use crate::html::render::search_index::get_function_type_for_search;
 use crate::html::render::IndexItem;
 
 /// This cache is used to store information about the [`clean::Crate`] being
@@ -303,7 +303,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                             desc,
                             parent,
                             parent_idx: None,
-                            search_type: get_index_search_type(&item, self.tcx, self.cache),
+                            search_type: get_function_type_for_search(&item, self.tcx),
                             aliases: item.attrs.get_doc_aliases(),
                         });
                     }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index e4c612aaab9..3a7c7186877 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -21,10 +21,12 @@ use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::CRATE_DEF_INDEX;
 use rustc_target::spec::abi::Abi;
 
-use crate::clean::{self, utils::find_nearest_parent_module, ExternalCrate, ItemId, PrimitiveType};
+use crate::clean::{
+    self, types::ExternalLocation, utils::find_nearest_parent_module, ExternalCrate, ItemId,
+    PrimitiveType,
+};
 use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
-use crate::html::render::cache::ExternalLocation;
 use crate::html::render::Context;
 
 use super::url_parts_builder::UrlPartsBuilder;
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 45a436c4487..534a542d58e 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -13,8 +13,8 @@ use rustc_span::edition::Edition;
 use rustc_span::source_map::FileName;
 use rustc_span::symbol::sym;
 
-use super::cache::{build_index, ExternalLocation};
 use super::print_item::{full_path, item_path, print_item};
+use super::search_index::build_index;
 use super::templates;
 use super::write_shared::write_shared;
 use super::{
@@ -22,7 +22,7 @@ use super::{
     BASIC_KEYWORDS,
 };
 
-use crate::clean::{self, ExternalCrate};
+use crate::clean::{self, types::ExternalLocation, ExternalCrate};
 use crate::config::RenderOptions;
 use crate::docfs::{DocFS, PathError};
 use crate::error::Error;
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index eb606178d24..3e7711181f7 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -23,7 +23,7 @@
 //! These threads are not parallelized (they haven't been a bottleneck yet), and
 //! both occur before the crate is rendered.
 
-crate mod cache;
+crate mod search_index;
 
 #[cfg(test)]
 mod tests;
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/search_index.rs
index 631eacc9618..0fbe090f219 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -7,22 +7,12 @@ use rustc_span::symbol::Symbol;
 use serde::ser::{Serialize, SerializeStruct, Serializer};
 
 use crate::clean;
-use crate::clean::types::{FnDecl, FnRetTy, GenericBound, Generics, Type, WherePredicate};
+use crate::clean::types::{FnRetTy, Function, GenericBound, Generics, Type, WherePredicate};
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::markdown::short_markdown_summary;
 use crate::html::render::{IndexItem, IndexItemFunctionType, RenderType, TypeWithKind};
 
-/// Indicates where an external crate can be found.
-crate enum ExternalLocation {
-    /// Remote URL root of the external crate
-    Remote(String),
-    /// This external crate can be found in the local doc/ folder
-    Local,
-    /// The external crate could not be found.
-    Unknown,
-}
-
 /// Builds the search index from the collected metadata
 crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<'tcx>) -> String {
     let mut defid_to_pathid = FxHashMap::default();
@@ -42,7 +32,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
                 desc,
                 parent: Some(did),
                 parent_idx: None,
-                search_type: get_index_search_type(item, tcx, cache),
+                search_type: get_function_type_for_search(item, tcx),
                 aliases: item.attrs.get_doc_aliases(),
             });
         }
@@ -191,15 +181,14 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
     )
 }
 
-crate fn get_index_search_type<'tcx>(
+crate fn get_function_type_for_search<'tcx>(
     item: &clean::Item,
     tcx: TyCtxt<'tcx>,
-    cache: &Cache,
 ) -> Option<IndexItemFunctionType> {
     let (mut inputs, mut output) = match *item.kind {
-        clean::FunctionItem(ref f) => get_all_types(&f.generics, &f.decl, tcx, cache),
-        clean::MethodItem(ref m, _) => get_all_types(&m.generics, &m.decl, tcx, cache),
-        clean::TyMethodItem(ref m) => get_all_types(&m.generics, &m.decl, tcx, cache),
+        clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx),
+        clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx),
+        clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx),
         _ => return None,
     };
 
@@ -211,12 +200,12 @@ crate fn get_index_search_type<'tcx>(
 
 fn get_index_type(clean_type: &clean::Type, generics: Vec<TypeWithKind>) -> RenderType {
     RenderType {
-        name: get_index_type_name(clean_type, true).map(|s| s.as_str().to_ascii_lowercase()),
+        name: get_index_type_name(clean_type).map(|s| s.as_str().to_ascii_lowercase()),
         generics: if generics.is_empty() { None } else { Some(generics) },
     }
 }
 
-fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option<Symbol> {
+fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> {
     match *clean_type {
         clean::Type::Path { ref path, .. } => {
             let path_segment = path.segments.last().unwrap();
@@ -226,11 +215,10 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option
             let path = &bounds[0].trait_;
             Some(path.segments.last().unwrap().name)
         }
-        clean::Generic(s) if accept_generic => Some(s),
+        clean::Generic(s) => Some(s),
         clean::Primitive(ref p) => Some(p.as_sym()),
-        clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic),
-        clean::Generic(_)
-        | clean::BareFunction(_)
+        clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_),
+        clean::BareFunction(_)
         | clean::Tuple(_)
         | clean::Slice(_)
         | clean::Array(_, _)
@@ -248,20 +236,19 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option
 ///
 /// Important note: It goes through generics recursively. So if you have
 /// `T: Option<Result<(), ()>>`, it'll go into `Option` and then into `Result`.
-crate fn get_real_types<'tcx>(
+#[instrument(level = "trace", skip(tcx, res))]
+fn add_generics_and_bounds_as_types<'tcx>(
     generics: &Generics,
     arg: &Type,
     tcx: TyCtxt<'tcx>,
     recurse: usize,
     res: &mut Vec<TypeWithKind>,
-    cache: &Cache,
 ) {
     fn insert_ty(
         res: &mut Vec<TypeWithKind>,
         tcx: TyCtxt<'_>,
         ty: Type,
         mut generics: Vec<TypeWithKind>,
-        _cache: &Cache,
     ) {
         let is_full_generic = ty.is_full_generic();
 
@@ -330,6 +317,7 @@ crate fn get_real_types<'tcx>(
 
     if recurse >= 10 {
         // FIXME: remove this whole recurse thing when the recursion bug is fixed
+        // See #59502 for the original issue.
         return;
     }
 
@@ -350,13 +338,12 @@ crate fn get_real_types<'tcx>(
                     for param_def in poly_trait.generic_params.iter() {
                         match &param_def.kind {
                             clean::GenericParamDefKind::Type { default: Some(ty), .. } => {
-                                get_real_types(
+                                add_generics_and_bounds_as_types(
                                     generics,
                                     ty,
                                     tcx,
                                     recurse + 1,
                                     &mut ty_generics,
-                                    cache,
                                 )
                             }
                             _ => {}
@@ -364,7 +351,7 @@ crate fn get_real_types<'tcx>(
                     }
                 }
             }
-            insert_ty(res, tcx, arg.clone(), ty_generics, cache);
+            insert_ty(res, tcx, arg.clone(), ty_generics);
         }
         // Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
         if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
@@ -372,10 +359,16 @@ crate fn get_real_types<'tcx>(
             for bound in bound.get_bounds().unwrap_or(&[]) {
                 if let Some(path) = bound.get_trait_path() {
                     let ty = Type::Path { path };
-                    get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics, cache);
+                    add_generics_and_bounds_as_types(
+                        generics,
+                        &ty,
+                        tcx,
+                        recurse + 1,
+                        &mut ty_generics,
+                    );
                 }
             }
-            insert_ty(res, tcx, arg.clone(), ty_generics, cache);
+            insert_ty(res, tcx, arg.clone(), ty_generics);
         }
     } else {
         // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
@@ -386,10 +379,10 @@ crate fn get_real_types<'tcx>(
         let mut ty_generics = Vec::new();
         if let Some(arg_generics) = arg.generics() {
             for gen in arg_generics.iter() {
-                get_real_types(generics, gen, tcx, recurse + 1, &mut ty_generics, cache);
+                add_generics_and_bounds_as_types(generics, gen, tcx, recurse + 1, &mut ty_generics);
             }
         }
-        insert_ty(res, tcx, arg.clone(), ty_generics, cache);
+        insert_ty(res, tcx, arg.clone(), ty_generics);
     }
 }
 
@@ -397,19 +390,20 @@ crate fn get_real_types<'tcx>(
 ///
 /// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return
 /// `[u32, Display, Option]`.
-crate fn get_all_types<'tcx>(
-    generics: &Generics,
-    decl: &FnDecl,
+fn get_fn_inputs_and_outputs<'tcx>(
+    func: &Function,
     tcx: TyCtxt<'tcx>,
-    cache: &Cache,
 ) -> (Vec<TypeWithKind>, Vec<TypeWithKind>) {
+    let decl = &func.decl;
+    let generics = &func.generics;
+
     let mut all_types = Vec::new();
     for arg in decl.inputs.values.iter() {
         if arg.type_.is_self_type() {
             continue;
         }
         let mut args = Vec::new();
-        get_real_types(generics, &arg.type_, tcx, 0, &mut args, cache);
+        add_generics_and_bounds_as_types(generics, &arg.type_, tcx, 0, &mut args);
         if !args.is_empty() {
             all_types.extend(args);
         } else {
@@ -423,7 +417,7 @@ crate fn get_all_types<'tcx>(
     let mut ret_types = Vec::new();
     match decl.output {
         FnRetTy::Return(ref return_type) => {
-            get_real_types(generics, return_type, tcx, 0, &mut ret_types, cache);
+            add_generics_and_bounds_as_types(generics, return_type, tcx, 0, &mut ret_types);
             if ret_types.is_empty() {
                 if let Some(kind) =
                     return_type.def_id_no_primitives().map(|did| tcx.def_kind(did).into())
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 0031e3915fa..005da01b52b 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -19,12 +19,11 @@ use rustc_session::Session;
 use rustdoc_json_types as types;
 
 use crate::clean;
-use crate::clean::ExternalCrate;
+use crate::clean::types::{ExternalCrate, ExternalLocation};
 use crate::config::RenderOptions;
 use crate::error::Error;
 use crate::formats::cache::Cache;
 use crate::formats::FormatRenderer;
-use crate::html::render::cache::ExternalLocation;
 use crate::json::conversions::{from_item_id, IntoWithTcx};
 
 #[derive(Clone)]
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index ba355107ed6..10ef92e5f40 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -684,27 +684,36 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 if ns != Namespace::ValueNS {
                     return None;
                 }
-                debug!("looking for variants or fields named {} for {:?}", item_name, did);
+                debug!("looking for fields named {} for {:?}", item_name, did);
                 // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?)
-                // NOTE: it's different from variant_field because it resolves fields and variants,
+                // NOTE: it's different from variant_field because it only resolves struct fields,
                 // not variant fields (2 path segments, not 3).
+                //
+                // We need to handle struct (and union) fields in this code because
+                // syntactically their paths are identical to associated item paths:
+                // `module::Type::field` and `module::Type::Assoc`.
+                //
+                // On the other hand, variant fields can't be mistaken for associated
+                // items because they look like this: `module::Type::Variant::field`.
+                //
+                // Variants themselves don't need to be handled here, even though
+                // they also look like associated items (`module::Type::Variant`),
+                // because they are real Rust syntax (unlike the intra-doc links
+                // field syntax) and are handled by the compiler's resolver.
                 let def = match tcx.type_of(did).kind() {
-                    ty::Adt(def, _) => def,
+                    ty::Adt(def, _) if !def.is_enum() => def,
                     _ => return None,
                 };
-                let field = if def.is_enum() {
-                    def.all_fields().find(|item| item.ident.name == item_name)
-                } else {
-                    def.non_enum_variant().fields.iter().find(|item| item.ident.name == item_name)
-                }?;
-                let kind = if def.is_enum() { DefKind::Variant } else { DefKind::Field };
-                let fragment = if def.is_enum() {
-                    // FIXME: how can the field be a variant?
-                    UrlFragment::Variant(field.ident.name)
-                } else {
-                    UrlFragment::StructField(field.ident.name)
-                };
-                Some((root_res, fragment, Some((kind, field.did))))
+                let field = def
+                    .non_enum_variant()
+                    .fields
+                    .iter()
+                    .find(|item| item.ident.name == item_name)?;
+                Some((
+                    root_res,
+                    UrlFragment::StructField(field.ident.name),
+                    Some((DefKind::Field, field.did)),
+                ))
             }
             Res::Def(DefKind::Trait, did) => tcx
                 .associated_items(did)
diff --git a/src/test/pretty/attr-fn-inner.rs b/src/test/pretty/attr-fn-inner.rs
index 0a745e7d34f..6d9cb89f022 100644
--- a/src/test/pretty/attr-fn-inner.rs
+++ b/src/test/pretty/attr-fn-inner.rs
@@ -9,8 +9,8 @@
 fn main() {
     #![rustc_dummy]
     #[rustc_dummy]
-    fn f() { }
+    fn f() {}
 
     #[rustc_dummy]
-    fn g() { }
+    fn g() {}
 }
diff --git a/src/test/pretty/attr-literals.rs b/src/test/pretty/attr-literals.rs
index 44d2c5db3e6..d132014420d 100644
--- a/src/test/pretty/attr-literals.rs
+++ b/src/test/pretty/attr-literals.rs
@@ -7,8 +7,8 @@
 fn main() {
     #![rustc_dummy("hi", 1, 2, 1.012, pi = 3.14, bye, name("John"))]
     #[rustc_dummy = 8]
-    fn f() { }
+    fn f() {}
 
     #[rustc_dummy(1, 2, 3)]
-    fn g() { }
+    fn g() {}
 }
diff --git a/src/test/pretty/attr-tokens-raw-ident.rs b/src/test/pretty/attr-tokens-raw-ident.rs
index bb2c4bb558e..8486342b087 100644
--- a/src/test/pretty/attr-tokens-raw-ident.rs
+++ b/src/test/pretty/attr-tokens-raw-ident.rs
@@ -4,4 +4,4 @@
 // pp-exact
 
 #[rustfmt::r#final(final)]
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/delimited-token-groups.rs b/src/test/pretty/delimited-token-groups.rs
index 257c032b536..1137d804564 100644
--- a/src/test/pretty/delimited-token-groups.rs
+++ b/src/test/pretty/delimited-token-groups.rs
@@ -45,4 +45,4 @@ mac! {
   }]
 #[rustc_dummy =
   "aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa"]
-fn main() { }
+fn main() {}
diff --git a/src/test/pretty/doc-comments.rs b/src/test/pretty/doc-comments.rs
index 2a98c9fc058..a49860daa6a 100644
--- a/src/test/pretty/doc-comments.rs
+++ b/src/test/pretty/doc-comments.rs
@@ -5,7 +5,7 @@
 // some single-line non-doc comment
 
 /// some single line outer-docs
-fn a() { }
+fn a() {}
 
 fn b() {
     //! some single line inner-docs
@@ -17,7 +17,7 @@ fn b() {
 //////////////////////////////////
 /// some single-line outer-docs preceded by a separator
 /// (and trailing whitespaces)
-fn c() { }
+fn c() {}
 
 /*
  * some multi-line non-doc comment
@@ -26,7 +26,7 @@ fn c() { }
 /**
  * some multi-line outer-docs
  */
-fn d() { }
+fn d() {}
 
 fn e() {
     /*!
@@ -43,10 +43,10 @@ fn e() {
 /**
  * some multi-line outer-docs preceded by a separator
  */
-fn f() { }
+fn f() {}
 
 #[doc = "unsugared outer doc-comments work also"]
-fn g() { }
+fn g() {}
 
 fn h() {
     #![doc = "as do inner ones"]
diff --git a/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs b/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs
new file mode 100644
index 00000000000..ce51556dd41
--- /dev/null
+++ b/src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+// Minimization of issue #59502
+
+trait MyTrait<T> {
+    type Output;
+}
+
+pub fn pow<T: MyTrait<T, Output = T>>(arg: T) -> T {
+    arg
+}
diff --git a/src/test/ui/error-codes/E0227.rs b/src/test/ui/error-codes/E0227.rs
new file mode 100644
index 00000000000..0f0a781d2f9
--- /dev/null
+++ b/src/test/ui/error-codes/E0227.rs
@@ -0,0 +1,12 @@
+trait Foo<'foo>: 'foo {}
+trait Bar<'bar>: 'bar {}
+
+trait FooBar<'foo, 'bar>: Foo<'foo> + Bar<'bar> {}
+
+struct Baz<'foo, 'bar> {
+    baz: dyn FooBar<'foo, 'bar>,
+    //~^ ERROR ambiguous lifetime bound, explicit lifetime bound required
+}
+
+fn main() {
+}
diff --git a/src/test/ui/error-codes/E0227.stderr b/src/test/ui/error-codes/E0227.stderr
new file mode 100644
index 00000000000..26de5b4c400
--- /dev/null
+++ b/src/test/ui/error-codes/E0227.stderr
@@ -0,0 +1,9 @@
+error[E0227]: ambiguous lifetime bound, explicit lifetime bound required
+  --> $DIR/E0227.rs:7:10
+   |
+LL |     baz: dyn FooBar<'foo, 'bar>,
+   |          ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0227`.
diff --git a/src/test/ui/macros/stringify.rs b/src/test/ui/macros/stringify.rs
index fcf6a9278d8..90bc7dc1da2 100644
--- a/src/test/ui/macros/stringify.rs
+++ b/src/test/ui/macros/stringify.rs
@@ -235,7 +235,7 @@ fn test_expr() {
             #[attr]
             {}
         ),
-        "#[attr] { }", // FIXME
+        "#[attr] {}",
     );
     assert_eq!(
         stringify_expr!(
@@ -803,7 +803,7 @@ fn test_ty() {
     assert_eq!(stringify_ty!(fn(x: u8)), "fn(x: u8)");
     #[rustfmt::skip]
     assert_eq!(stringify_ty!(for<> fn()), "fn()");
-    assert_eq!(stringify_ty!(for<'a> fn()), "for<'a>fn()"); // FIXME
+    assert_eq!(stringify_ty!(for<'a> fn()), "for<'a> fn()");
 
     // TyKind::Never
     assert_eq!(stringify_ty!(!), "!");
diff --git a/src/test/ui/match/expr_before_ident_pat.rs b/src/test/ui/match/expr_before_ident_pat.rs
new file mode 100644
index 00000000000..47db6c3f488
--- /dev/null
+++ b/src/test/ui/match/expr_before_ident_pat.rs
@@ -0,0 +1,15 @@
+#![feature(half_open_range_patterns)]
+
+macro_rules! funny {
+    ($a:expr, $b:ident) => {
+        match [1, 2] {
+            [$a, $b] => {}
+        }
+    };
+}
+
+fn main() {
+    funny!(a, a);
+    //~^ ERROR cannot find value `a` in this scope
+    //~| ERROR arbitrary expressions aren't allowed in patterns
+}
diff --git a/src/test/ui/match/expr_before_ident_pat.stderr b/src/test/ui/match/expr_before_ident_pat.stderr
new file mode 100644
index 00000000000..1ac8274ffd5
--- /dev/null
+++ b/src/test/ui/match/expr_before_ident_pat.stderr
@@ -0,0 +1,15 @@
+error: arbitrary expressions aren't allowed in patterns
+  --> $DIR/expr_before_ident_pat.rs:12:12
+   |
+LL |     funny!(a, a);
+   |            ^
+
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/expr_before_ident_pat.rs:12:12
+   |
+LL |     funny!(a, a);
+   |            ^ not found in this scope
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/match/issue-92100.rs b/src/test/ui/match/issue-92100.rs
new file mode 100644
index 00000000000..021166b2ba5
--- /dev/null
+++ b/src/test/ui/match/issue-92100.rs
@@ -0,0 +1,7 @@
+#![feature(half_open_range_patterns)]
+
+fn main() {
+    match [1, 2] {
+        [a.., a] => {} //~ ERROR cannot find value `a` in this scope
+    }
+}
diff --git a/src/test/ui/match/issue-92100.stderr b/src/test/ui/match/issue-92100.stderr
new file mode 100644
index 00000000000..0f694c587fc
--- /dev/null
+++ b/src/test/ui/match/issue-92100.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/issue-92100.rs:5:10
+   |
+LL |         [a.., a] => {}
+   |          ^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/parser/type-alias-where.rs b/src/test/ui/parser/type-alias-where.rs
new file mode 100644
index 00000000000..a9fa23dd95e
--- /dev/null
+++ b/src/test/ui/parser/type-alias-where.rs
@@ -0,0 +1,37 @@
+// check-fail
+
+#![feature(generic_associated_types)]
+
+// Fine, but lints as unused
+type Foo where u32: Copy = ();
+// Not fine.
+type Bar = () where u32: Copy;
+//~^ ERROR where clause not allowed here
+type Baz = () where;
+//~^ ERROR where clause not allowed here
+
+trait Trait {
+    // Fine.
+    type Assoc where u32: Copy;
+    // Fine.
+    type Assoc2 where u32: Copy, i32: Copy;
+}
+
+impl Trait for u32 {
+    // Fine.
+    type Assoc where u32: Copy = ();
+    // Not fine, suggests moving `i32: Copy`
+    type Assoc2 where u32: Copy = () where i32: Copy;
+    //~^ ERROR where clause not allowed here
+}
+
+impl Trait for i32 {
+    // Not fine, suggests moving `u32: Copy`
+    type Assoc = () where u32: Copy;
+    //~^ ERROR where clause not allowed here
+    // Not fine, suggests moving both.
+    type Assoc2 = () where u32: Copy, i32: Copy;
+    //~^ ERROR where clause not allowed here
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/type-alias-where.stderr b/src/test/ui/parser/type-alias-where.stderr
new file mode 100644
index 00000000000..7ab0b28c864
--- /dev/null
+++ b/src/test/ui/parser/type-alias-where.stderr
@@ -0,0 +1,40 @@
+error: where clause not allowed here
+  --> $DIR/type-alias-where.rs:8:15
+   |
+LL | type Bar = () where u32: Copy;
+   |         -     ^^^^^^^^^^^^^^^
+   |         |
+   |         help: move it here: `where u32: Copy`
+
+error: where clause not allowed here
+  --> $DIR/type-alias-where.rs:10:15
+   |
+LL | type Baz = () where;
+   |               ^^^^^
+
+error: where clause not allowed here
+  --> $DIR/type-alias-where.rs:24:38
+   |
+LL |     type Assoc2 where u32: Copy = () where i32: Copy;
+   |                                -     ^^^^^^^^^^^^^^^
+   |                                |
+   |                                help: move it here: `, i32: Copy`
+
+error: where clause not allowed here
+  --> $DIR/type-alias-where.rs:30:21
+   |
+LL |     type Assoc = () where u32: Copy;
+   |               -     ^^^^^^^^^^^^^^^
+   |               |
+   |               help: move it here: `where u32: Copy`
+
+error: where clause not allowed here
+  --> $DIR/type-alias-where.rs:33:22
+   |
+LL |     type Assoc2 = () where u32: Copy, i32: Copy;
+   |                -     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                |
+   |                help: move it here: `where u32: Copy, i32: Copy`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs
index 6d3e470bf43..8ea6bb308b7 100644
--- a/src/tools/tidy/src/error_codes_check.rs
+++ b/src/tools/tidy/src/error_codes_check.rs
@@ -10,8 +10,8 @@ use regex::Regex;
 
 // A few of those error codes can't be tested but all the others can and *should* be tested!
 const EXEMPTED_FROM_TEST: &[&str] = &[
-    "E0227", "E0279", "E0280", "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0514",
-    "E0519", "E0523", "E0554", "E0640", "E0717", "E0729",
+    "E0279", "E0280", "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0514", "E0519",
+    "E0523", "E0554", "E0640", "E0717", "E0729",
 ];
 
 // Some error codes don't have any tests apparently...