From b1529a680a9a593bd0cb01502dc86b7d0e3ee28d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 23 Dec 2021 16:03:30 -0800 Subject: [PATCH 01/15] Visit patterns' literal expressions before binding new idents --- compiler/rustc_resolve/src/late.rs | 5 ++++- src/test/ui/match/expr_before_ident_pat.rs | 15 +++++++++++++++ src/test/ui/match/expr_before_ident_pat.stderr | 15 +++++++++++++++ src/test/ui/match/issue-92100.rs | 7 +++++++ src/test/ui/match/issue-92100.stderr | 9 +++++++++ 5 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/match/expr_before_ident_pat.rs create mode 100644 src/test/ui/match/expr_before_ident_pat.stderr create mode 100644 src/test/ui/match/issue-92100.rs create mode 100644 src/test/ui/match/issue-92100.stderr diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 12123c946cc0..5098cef11e83 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); 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/test/ui/match/expr_before_ident_pat.rs b/src/test/ui/match/expr_before_ident_pat.rs new file mode 100644 index 000000000000..47db6c3f4880 --- /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 000000000000..1ac8274ffd5d --- /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 000000000000..021166b2ba56 --- /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 000000000000..0f694c587fcb --- /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`. From 60a1abe4c5b6399e62144fc94d236b6f7eefcdf0 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 27 Dec 2021 18:39:35 -0800 Subject: [PATCH 02/15] Rename `rustdoc::html::render::cache` to `search_index` The old name wasn't very clear, while the new one makes it clear that this is the code responsible for creating the search index. --- src/librustdoc/clean/types.rs | 2 +- src/librustdoc/formats/cache.rs | 2 +- src/librustdoc/html/format.rs | 2 +- src/librustdoc/html/render/context.rs | 2 +- src/librustdoc/html/render/mod.rs | 2 +- src/librustdoc/html/render/{cache.rs => search_index.rs} | 0 src/librustdoc/json/mod.rs | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename src/librustdoc/html/render/{cache.rs => search_index.rs} (100%) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index fe32b75d668c..f0e6d4315648 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -38,7 +38,7 @@ 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::search_index::ExternalLocation; use crate::html::render::Context; crate use self::FnRetTy::*; diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 5813062ceab7..8a5c8651f999 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -12,7 +12,7 @@ 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_index_search_type, ExternalLocation}; use crate::html::render::IndexItem; /// This cache is used to store information about the [`clean::Crate`] being diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 3a2effa625cf..f7396f758b10 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -24,7 +24,7 @@ use rustc_target::spec::abi::Abi; use crate::clean::{self, 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::search_index::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 45a436c44871..6729129027f5 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, ExternalLocation}; use super::templates; use super::write_shared::write_shared; use super::{ diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index eb606178d244..3e7711181f73 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 similarity index 100% rename from src/librustdoc/html/render/cache.rs rename to src/librustdoc/html/render/search_index.rs diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 0031e3915fa4..01641bae3845 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -24,7 +24,7 @@ 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::html::render::search_index::ExternalLocation; use crate::json::conversions::{from_item_id, IntoWithTcx}; #[derive(Clone)] From e19593f0e51196dc3528bb5fa8b89e81ae493092 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 27 Dec 2021 18:53:00 -0800 Subject: [PATCH 03/15] rustdoc: Remove some unnecessary `cache` parameters Based on https://github.com/rust-lang/rust/pull/80883#issuecomment-774437832. The `tcx` parameters do seem to be used though, so I only removed the `cache` parameters. --- src/librustdoc/formats/cache.rs | 2 +- src/librustdoc/html/render/search_index.rs | 35 ++++++++-------------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 8a5c8651f999..528d48a8d059 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -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_index_search_type(&item, self.tcx), aliases: item.attrs.get_doc_aliases(), }); } diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 631eacc96182..5d4df3ee5ff3 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -42,7 +42,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_index_search_type(item, tcx), aliases: item.attrs.get_doc_aliases(), }); } @@ -194,12 +194,11 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt< crate fn get_index_search_type<'tcx>( item: &clean::Item, tcx: TyCtxt<'tcx>, - cache: &Cache, ) -> Option { 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_all_types(&f.generics, &f.decl, tcx), + clean::MethodItem(ref m, _) => get_all_types(&m.generics, &m.decl, tcx), + clean::TyMethodItem(ref m) => get_all_types(&m.generics, &m.decl, tcx), _ => return None, }; @@ -254,14 +253,12 @@ crate fn get_real_types<'tcx>( tcx: TyCtxt<'tcx>, recurse: usize, res: &mut Vec, - cache: &Cache, ) { fn insert_ty( res: &mut Vec, tcx: TyCtxt<'_>, ty: Type, mut generics: Vec, - _cache: &Cache, ) { let is_full_generic = ty.is_full_generic(); @@ -350,21 +347,14 @@ crate fn get_real_types<'tcx>( for param_def in poly_trait.generic_params.iter() { match ¶m_def.kind { clean::GenericParamDefKind::Type { default: Some(ty), .. } => { - get_real_types( - generics, - ty, - tcx, - recurse + 1, - &mut ty_generics, - cache, - ) + get_real_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); } // Otherwise we check if the trait bounds are "inlined" like `T: Option`... if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) { @@ -372,10 +362,10 @@ 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); + get_real_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`, and we're @@ -386,10 +376,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); + get_real_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); } } @@ -401,7 +391,6 @@ crate fn get_all_types<'tcx>( generics: &Generics, decl: &FnDecl, tcx: TyCtxt<'tcx>, - cache: &Cache, ) -> (Vec, Vec) { let mut all_types = Vec::new(); for arg in decl.inputs.values.iter() { @@ -409,7 +398,7 @@ crate fn get_all_types<'tcx>( continue; } let mut args = Vec::new(); - get_real_types(generics, &arg.type_, tcx, 0, &mut args, cache); + get_real_types(generics, &arg.type_, tcx, 0, &mut args); if !args.is_empty() { all_types.extend(args); } else { @@ -423,7 +412,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); + get_real_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()) From 2b801dcdd303e3e2a92e255d8cfb9427800403e5 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 27 Dec 2021 18:57:07 -0800 Subject: [PATCH 04/15] Move `ExternalLocation` to `clean::types` It was previously defined in `render::search_index` but wasn't used at all there. `clean::types` seems like a better fit since that's where `ExternalCrate` is defined. --- src/librustdoc/clean/types.rs | 11 ++++++++++- src/librustdoc/formats/cache.rs | 4 ++-- src/librustdoc/html/format.rs | 6 ++++-- src/librustdoc/html/render/context.rs | 4 ++-- src/librustdoc/html/render/search_index.rs | 10 ---------- src/librustdoc/json/mod.rs | 3 +-- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index f0e6d4315648..861b70bac6c4 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -38,7 +38,6 @@ use crate::clean::Clean; use crate::core::DocContext; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; -use crate::html::render::search_index::ExternalLocation; use crate::html::render::Context; crate use self::FnRetTy::*; @@ -337,6 +336,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 528d48a8d059..4dbf3b64a3d1 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::search_index::{get_index_search_type, ExternalLocation}; +use crate::html::render::search_index::get_index_search_type; use crate::html::render::IndexItem; /// This cache is used to store information about the [`clean::Crate`] being diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index f7396f758b10..4088163df391 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::search_index::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 6729129027f5..534a542d58ed 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -14,7 +14,7 @@ use rustc_span::source_map::FileName; use rustc_span::symbol::sym; use super::print_item::{full_path, item_path, print_item}; -use super::search_index::{build_index, ExternalLocation}; +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/search_index.rs b/src/librustdoc/html/render/search_index.rs index 5d4df3ee5ff3..787f047790ae 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -13,16 +13,6 @@ 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(); diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 01641bae3845..005da01b52b6 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::search_index::ExternalLocation; use crate::json::conversions::{from_item_id, IntoWithTcx}; #[derive(Clone)] From bd6692c50dd97a5679dbe0c8f23cc1b844c4cefe Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 27 Dec 2021 18:59:27 -0800 Subject: [PATCH 05/15] Make `search_index` functions private where possible Now the only two crate-public items are `build_index` and `get_index_search_type` (because for some reason the latter is also used in `formats::cache`). --- src/librustdoc/html/render/search_index.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 787f047790ae..e03f96aeb471 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -237,7 +237,7 @@ 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>`, it'll go into `Option` and then into `Result`. -crate fn get_real_types<'tcx>( +fn get_real_types<'tcx>( generics: &Generics, arg: &Type, tcx: TyCtxt<'tcx>, @@ -377,7 +377,7 @@ crate fn get_real_types<'tcx>( /// /// i.e. `fn foo>(x: u32, y: B)` will return /// `[u32, Display, Option]`. -crate fn get_all_types<'tcx>( +fn get_all_types<'tcx>( generics: &Generics, decl: &FnDecl, tcx: TyCtxt<'tcx>, From afb77a959a45571ea6180053a63a25c752995380 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 27 Dec 2021 19:16:33 -0800 Subject: [PATCH 06/15] Coalesce two arguments as `&Function` --- src/librustdoc/html/render/search_index.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index e03f96aeb471..90e73f4a76d8 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -7,7 +7,7 @@ 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; @@ -186,9 +186,9 @@ crate fn get_index_search_type<'tcx>( tcx: TyCtxt<'tcx>, ) -> Option { let (mut inputs, mut output) = match *item.kind { - clean::FunctionItem(ref f) => get_all_types(&f.generics, &f.decl, tcx), - clean::MethodItem(ref m, _) => get_all_types(&m.generics, &m.decl, tcx), - clean::TyMethodItem(ref m) => get_all_types(&m.generics, &m.decl, tcx), + clean::FunctionItem(ref f) => get_all_types(f, tcx), + clean::MethodItem(ref m, _) => get_all_types(m, tcx), + clean::TyMethodItem(ref m) => get_all_types(m, tcx), _ => return None, }; @@ -378,10 +378,12 @@ fn get_real_types<'tcx>( /// i.e. `fn foo>(x: u32, y: B)` will return /// `[u32, Display, Option]`. fn get_all_types<'tcx>( - generics: &Generics, - decl: &FnDecl, + func: &Function, tcx: TyCtxt<'tcx>, ) -> (Vec, Vec) { + 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() { From 5c8e8e565d854f72691031262fcf945bcf1f24f9 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 27 Dec 2021 19:19:56 -0800 Subject: [PATCH 07/15] Give clearer names to several search index functions --- src/librustdoc/formats/cache.rs | 4 +-- src/librustdoc/html/render/search_index.rs | 36 ++++++++++++++-------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 4dbf3b64a3d1..6b9ccd37cfb3 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -12,7 +12,7 @@ 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::search_index::get_index_search_type; +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), + search_type: get_function_type_for_search(&item, self.tcx), aliases: item.attrs.get_doc_aliases(), }); } diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 90e73f4a76d8..9543afc68a40 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -32,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), + search_type: get_function_type_for_search(item, tcx), aliases: item.attrs.get_doc_aliases(), }); } @@ -181,14 +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>, ) -> Option { let (mut inputs, mut output) = match *item.kind { - clean::FunctionItem(ref f) => get_all_types(f, tcx), - clean::MethodItem(ref m, _) => get_all_types(m, tcx), - clean::TyMethodItem(ref m) => get_all_types(m, tcx), + 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, }; @@ -237,7 +237,7 @@ 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>`, it'll go into `Option` and then into `Result`. -fn get_real_types<'tcx>( +fn add_generics_and_bounds_as_types<'tcx>( generics: &Generics, arg: &Type, tcx: TyCtxt<'tcx>, @@ -337,7 +337,13 @@ fn get_real_types<'tcx>( for param_def in poly_trait.generic_params.iter() { match ¶m_def.kind { clean::GenericParamDefKind::Type { default: Some(ty), .. } => { - get_real_types(generics, ty, tcx, recurse + 1, &mut ty_generics) + add_generics_and_bounds_as_types( + generics, + ty, + tcx, + recurse + 1, + &mut ty_generics, + ) } _ => {} } @@ -352,7 +358,13 @@ 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); + add_generics_and_bounds_as_types( + generics, + &ty, + tcx, + recurse + 1, + &mut ty_generics, + ); } } insert_ty(res, tcx, arg.clone(), ty_generics); @@ -366,7 +378,7 @@ 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); + add_generics_and_bounds_as_types(generics, gen, tcx, recurse + 1, &mut ty_generics); } } insert_ty(res, tcx, arg.clone(), ty_generics); @@ -377,7 +389,7 @@ fn get_real_types<'tcx>( /// /// i.e. `fn foo>(x: u32, y: B)` will return /// `[u32, Display, Option]`. -fn get_all_types<'tcx>( +fn get_fn_inputs_and_outputs<'tcx>( func: &Function, tcx: TyCtxt<'tcx>, ) -> (Vec, Vec) { @@ -390,7 +402,7 @@ fn get_all_types<'tcx>( continue; } let mut args = Vec::new(); - get_real_types(generics, &arg.type_, tcx, 0, &mut args); + add_generics_and_bounds_as_types(generics, &arg.type_, tcx, 0, &mut args); if !args.is_empty() { all_types.extend(args); } else { @@ -404,7 +416,7 @@ 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); + 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()) From 406d6d4028260f6c5ff02562831c137c41e0bb95 Mon Sep 17 00:00:00 2001 From: TmLev Date: Tue, 28 Dec 2021 15:46:20 +0300 Subject: [PATCH 08/15] docs(error-codes): Add long error explanation for E0227 --- compiler/rustc_error_codes/src/error_codes.rs | 2 +- .../src/error_codes/E0227.md | 33 +++++++++++++++++++ src/test/ui/error-codes/E0227.rs | 12 +++++++ src/test/ui/error-codes/E0227.stderr | 9 +++++ src/tools/tidy/src/error_codes_check.rs | 4 +-- 5 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0227.md create mode 100644 src/test/ui/error-codes/E0227.rs create mode 100644 src/test/ui/error-codes/E0227.stderr diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index ce26ff62235f..79d9c55b5470 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 000000000000..f68614723d44 --- /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/src/test/ui/error-codes/E0227.rs b/src/test/ui/error-codes/E0227.rs new file mode 100644 index 000000000000..0f0a781d2f9d --- /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 000000000000..26de5b4c4001 --- /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/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index 6d3e470bf43c..8ea6bb308b7b 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... From 4391a11537ce38c919058c292e91f059d658da94 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Mon, 20 Dec 2021 09:10:10 -0500 Subject: [PATCH 09/15] Parse and suggest moving where clauses after equals for type aliases --- compiler/rustc_ast_pretty/src/pprust/state.rs | 56 +++++++++---------- compiler/rustc_parse/src/parser/item.rs | 53 ++++++++++++++++++ src/test/ui/parser/type-alias-where.rs | 37 ++++++++++++ src/test/ui/parser/type-alias-where.stderr | 40 +++++++++++++ 4 files changed, 158 insertions(+), 28 deletions(-) create mode 100644 src/test/ui/parser/type-alias-where.rs create mode 100644 src/test/ui/parser/type-alias-where.stderr diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 6c5b38bc4bb1..4464b5eee963 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -2780,34 +2780,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); } } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 618aa3fd002a..d335ef8788b8 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/src/test/ui/parser/type-alias-where.rs b/src/test/ui/parser/type-alias-where.rs new file mode 100644 index 000000000000..a9fa23dd95ef --- /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 000000000000..7ab0b28c8640 --- /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 + From cbccc4a59770f5124762e5fdb2085ff8b04e51cd Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 28 Dec 2021 12:26:18 -0800 Subject: [PATCH 10/15] Remove pretty printer space inside block with only outer attrs --- compiler/rustc_ast_pretty/src/pprust/state.rs | 23 ++++++++++--------- src/test/pretty/attr-fn-inner.rs | 4 ++-- src/test/pretty/attr-literals.rs | 4 ++-- src/test/pretty/attr-tokens-raw-ident.rs | 2 +- src/test/pretty/delimited-token-groups.rs | 2 +- src/test/pretty/doc-comments.rs | 10 ++++---- src/test/ui/macros/stringify.rs | 2 +- 7 files changed, 24 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 6c5b38bc4bb1..eb6ea8e5fe4d 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 + 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 + 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)) } diff --git a/src/test/pretty/attr-fn-inner.rs b/src/test/pretty/attr-fn-inner.rs index 0a745e7d34fc..6d9cb89f0229 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 44d2c5db3e66..d132014420df 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 bb2c4bb558e5..8486342b0879 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 257c032b536d..1137d8045648 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 2a98c9fc0589..a49860daa6ad 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/ui/macros/stringify.rs b/src/test/ui/macros/stringify.rs index fcf6a9278d8f..f284ac727f4b 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!( From 636d6a3eec8b7505beb18633bce1bc51835fceca Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 18 Dec 2021 09:48:51 -0600 Subject: [PATCH 11/15] Only special case struct fields for intra-doc links, not enum variants Variants are already handled by `resolve_str_path_error`, rustdoc doesn't need to consider them separately. --- .../passes/collect_intra_doc_links.rs | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index ba355107ed68..27d8b8f2e3bd 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -684,27 +684,24 @@ 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). 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) From ad29c177f463f1c4af5bc0dfc36d0bd262198067 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 23 Dec 2021 12:31:37 -0800 Subject: [PATCH 12/15] Print space after formal generic params in fn type --- compiler/rustc_ast_pretty/src/pprust/state.rs | 5 +---- compiler/rustc_hir_pretty/src/lib.rs | 5 +---- src/test/ui/macros/stringify.rs | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 6c5b38bc4bb1..7e71492a2215 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -2908,10 +2908,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_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 2f5f158856f1..334fa6f4e5cc 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/src/test/ui/macros/stringify.rs b/src/test/ui/macros/stringify.rs index fcf6a9278d8f..2a722202fefb 100644 --- a/src/test/ui/macros/stringify.rs +++ b/src/test/ui/macros/stringify.rs @@ -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!(!), "!"); From 7d1ec648914d59a6620ed0dcc2ed60c86b53f189 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 27 Dec 2021 19:28:05 -0800 Subject: [PATCH 13/15] Remove unused parameter --- src/librustdoc/html/render/search_index.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 9543afc68a40..038ee351545f 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -200,12 +200,12 @@ crate fn get_function_type_for_search<'tcx>( fn get_index_type(clean_type: &clean::Type, generics: Vec) -> 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 { +fn get_index_type_name(clean_type: &clean::Type) -> Option { match *clean_type { clean::Type::Path { ref path, .. } => { let path_segment = path.segments.last().unwrap(); @@ -215,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(_, _) From 09104adda4603be1aa734bd32c69dfdac006aadf Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Tue, 28 Dec 2021 11:40:06 -0800 Subject: [PATCH 14/15] Explain why struct fields are handled by assoc. item code --- src/librustdoc/passes/collect_intra_doc_links.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 27d8b8f2e3bd..10ef92e5f400 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -688,6 +688,18 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?) // 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, _) if !def.is_enum() => def, _ => return None, From 908a9d4aad61f4b8108ff91ae42f76e67dec5148 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Tue, 28 Dec 2021 13:15:02 -0800 Subject: [PATCH 15/15] Add regression test for #59502 This issue was fixed using a hacky recursion "fuel" argument, but the issue was never minimized nor was a regression test added. The underlying bug is still unfixed, so this test should help with fixing it and removing the `recurse` hack. --- src/librustdoc/html/render/search_index.rs | 2 ++ ...search-index-generics-recursion-bug-issue-59502.rs | 11 +++++++++++ 2 files changed, 13 insertions(+) create mode 100644 src/test/rustdoc-ui/search-index-generics-recursion-bug-issue-59502.rs diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 038ee351545f..0fbe090f2190 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -236,6 +236,7 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option { /// /// Important note: It goes through generics recursively. So if you have /// `T: Option>`, it'll go into `Option` and then into `Result`. +#[instrument(level = "trace", skip(tcx, res))] fn add_generics_and_bounds_as_types<'tcx>( generics: &Generics, arg: &Type, @@ -316,6 +317,7 @@ fn add_generics_and_bounds_as_types<'tcx>( if recurse >= 10 { // FIXME: remove this whole recurse thing when the recursion bug is fixed + // See #59502 for the original issue. return; } 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 000000000000..ce51556dd418 --- /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 { + type Output; +} + +pub fn pow>(arg: T) -> T { + arg +}