diff options
62 files changed, 757 insertions, 473 deletions
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 21cf214e47c..cd3c620cbb7 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -92,7 +92,7 @@ impl DefPathTable { /// The definition table containing node definitions. /// It holds the `DefPathTable` for `LocalDefId`s/`DefPath`s. /// It also stores mappings to convert `LocalDefId`s to/from `HirId`s. -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct Definitions { table: DefPathTable, next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a063307af0c..7cb3b6e1525 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3460,7 +3460,7 @@ pub struct Upvar { // The TraitCandidate's import_ids is empty if the trait is defined in the same module, and // has length > 0 if the trait is found through an chain of imports, starting with the // import/use statement in the scope where the trait is used. -#[derive(Encodable, Decodable, Clone, Debug, HashStable_Generic)] +#[derive(Encodable, Decodable, Debug, HashStable_Generic)] pub struct TraitCandidate { pub def_id: DefId, pub import_ids: SmallVec<[LocalDefId; 1]>, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 33ebbb411ce..c8d8afae39e 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -35,13 +35,11 @@ use rustc_target::spec::PanicStrategy; use rustc_trait_selection::traits; use std::any::Any; -use std::cell::RefCell; use std::ffi::OsString; use std::io::{self, BufWriter, Write}; use std::marker::PhantomPinned; use std::path::{Path, PathBuf}; use std::pin::Pin; -use std::rc::Rc; use std::sync::{Arc, LazyLock}; use std::{env, fs, iter}; @@ -131,21 +129,12 @@ mod boxed_resolver { f((&mut *resolver).as_mut().unwrap()) } - pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ty::ResolverOutputs { - match Rc::try_unwrap(resolver) { - Ok(resolver) => { - let mut resolver = resolver.into_inner(); - // SAFETY: The resolver doesn't need to be pinned. - let mut resolver = unsafe { - resolver - .0 - .as_mut() - .map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver) - }; - resolver.take().unwrap().into_outputs() - } - Err(resolver) => resolver.borrow_mut().access(|resolver| resolver.clone_outputs()), - } + pub fn into_outputs(mut self) -> ty::ResolverOutputs { + // SAFETY: The resolver doesn't need to be pinned. + let mut resolver = unsafe { + self.0.as_mut().map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver) + }; + resolver.take().unwrap().into_outputs() } } } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 6512695873e..67886b6b989 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -21,7 +21,6 @@ use rustc_span::symbol::sym; use rustc_span::Symbol; use std::any::Any; use std::cell::{RefCell, RefMut}; -use std::rc::Rc; use std::sync::Arc; /// Represent the result of a query. @@ -88,7 +87,7 @@ pub struct Queries<'tcx> { parse: Query<ast::Crate>, crate_name: Query<Symbol>, register_plugins: Query<(ast::Crate, Lrc<LintStore>)>, - expansion: Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>, + expansion: Query<(Lrc<ast::Crate>, BoxedResolver, Lrc<LintStore>)>, dep_graph: Query<DepGraph>, // This just points to what's in `gcx_cell`. gcx: Query<&'tcx GlobalCtxt<'tcx>>, @@ -171,8 +170,7 @@ impl<'tcx> Queries<'tcx> { pub fn expansion( &self, - ) -> Result<QueryResult<'_, (Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>> - { + ) -> Result<QueryResult<'_, (Lrc<ast::Crate>, BoxedResolver, Lrc<LintStore>)>> { trace!("expansion"); self.expansion.compute(|| { let crate_name = *self.crate_name()?.borrow(); @@ -188,7 +186,7 @@ impl<'tcx> Queries<'tcx> { let krate = resolver.access(|resolver| { passes::configure_and_expand(sess, &lint_store, krate, crate_name, resolver) })?; - Ok((Lrc::new(krate), Rc::new(RefCell::new(resolver)), lint_store)) + Ok((Lrc::new(krate), resolver, lint_store)) }) } @@ -217,7 +215,7 @@ impl<'tcx> Queries<'tcx> { untracked, global_ctxt: untracked_resolutions, ast_lowering: untracked_resolver_for_lowering, - } = BoxedResolver::to_resolver_outputs(resolver); + } = resolver.into_outputs(); let gcx = passes::create_global_ctxt( self.compiler, diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index d1d4bb37528..972240f42cf 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -837,9 +837,17 @@ pub trait LintContext: Sized { (use_span, "'_".to_owned()) }; debug!(?deletion_span, ?use_span); + + // issue 107998 for the case such as a wrong function pointer type + // `deletion_span` is empty and there is no need to report lifetime uses here + let suggestions = if deletion_span.is_empty() { + vec![(use_span, replace_lt)] + } else { + vec![(deletion_span, String::new()), (use_span, replace_lt)] + }; db.multipart_suggestion( msg, - vec![(deletion_span, String::new()), (use_span, replace_lt)], + suggestions, Applicability::MachineApplicable, ); } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index bf8b8aa2ce4..c357f294279 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -8,7 +8,7 @@ use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::{self as ast, *}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{Lrc, ReadGuard}; +use rustc_data_structures::sync::ReadGuard; use rustc_expand::base::SyntaxExtension; use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; @@ -30,11 +30,10 @@ use proc_macro::bridge::client::ProcMacro; use std::ops::Fn; use std::path::Path; use std::time::Duration; -use std::{cmp, env}; +use std::{cmp, env, iter}; -#[derive(Clone)] pub struct CStore { - metas: IndexVec<CrateNum, Option<Lrc<CrateMetadata>>>, + metas: IndexVec<CrateNum, Option<Box<CrateMetadata>>>, injected_panic_runtime: Option<CrateNum>, /// This crate needs an allocator and either provides it itself, or finds it in a dependency. /// If the above is true, then this field denotes the kind of the found allocator. @@ -153,7 +152,7 @@ impl CStore { fn set_crate_data(&mut self, cnum: CrateNum, data: CrateMetadata) { assert!(self.metas[cnum].is_none(), "Overwriting crate metadata entry"); - self.metas[cnum] = Some(Lrc::new(data)); + self.metas[cnum] = Some(Box::new(data)); } pub(crate) fn iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMetadata)> { @@ -245,7 +244,7 @@ impl CStore { // order to make array indices in `metas` match with the // corresponding `CrateNum`. This first entry will always remain // `None`. - metas: IndexVec::from_elem_n(None, 1), + metas: IndexVec::from_iter(iter::once(None)), injected_panic_runtime: None, allocator_kind: None, alloc_error_handler_kind: None, diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 800f85063c4..3457e51f8e6 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1169,15 +1169,9 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } /// Decodes all trait impls in the crate (for rustdoc). - fn get_trait_impls(self) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + 'a { - self.cdata.trait_impls.iter().flat_map(move |(&(trait_cnum_raw, trait_index), impls)| { - let trait_def_id = DefId { - krate: self.cnum_map[CrateNum::from_u32(trait_cnum_raw)], - index: trait_index, - }; - impls.decode(self).map(move |(impl_index, simplified_self_ty)| { - (trait_def_id, self.local_def_id(impl_index), simplified_self_ty) - }) + fn get_trait_impls(self) -> impl Iterator<Item = DefId> + 'a { + self.cdata.trait_impls.values().flat_map(move |impls| { + impls.decode(self).map(move |(impl_index, _)| self.local_def_id(impl_index)) }) } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index b12f9b5c917..8082a890320 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -304,6 +304,7 @@ provide! { tcx, def_id, other, cdata, extra_filename => { cdata.root.extra_filename.clone() } traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) } + trait_impls_in_crate => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) } implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) } crate_incoherent_impls => { cdata.get_incoherent_impls(tcx, other) } @@ -608,20 +609,6 @@ impl CStore { ) -> Span { self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess) } - - /// Decodes all trait impls in the crate (for rustdoc). - pub fn trait_impls_in_crate_untracked( - &self, - cnum: CrateNum, - ) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + '_ { - self.get_crate_data(cnum).get_trait_impls() - } - - pub fn is_doc_hidden_untracked(&self, def_id: DefId) -> bool { - self.get_crate_data(def_id.krate) - .get_attr_flags(def_id.index) - .contains(AttrFlags::IS_DOC_HIDDEN) - } } impl CrateStore for CStore { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 263c71ae702..060ade8a42f 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -2256,6 +2256,22 @@ pub fn provide(providers: &mut Providers) { traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id)); tcx.arena.alloc_slice(&traits) }, + trait_impls_in_crate: |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + + let mut trait_impls = Vec::new(); + for id in tcx.hir().items() { + if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) + && tcx.impl_trait_ref(id.owner_id).is_some() + { + trait_impls.push(id.owner_id.to_def_id()) + } + } + + // Bring everything into deterministic order. + trait_impls.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id)); + tcx.arena.alloc_slice(&trait_impls) + }, ..*providers } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d37d6b37a37..71c9058a696 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1836,6 +1836,11 @@ rustc_queries! { separate_provide_extern } + query trait_impls_in_crate(_: CrateNum) -> &'tcx [DefId] { + desc { "fetching all trait impls in a crate" } + separate_provide_extern + } + /// The list of symbols exported from the given crate. /// /// - All names contained in `exported_symbols(cnum)` are guaranteed to diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 4ed0484438f..6d8c9d73763 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -187,6 +187,7 @@ pub struct ResolverGlobalCtxt { pub registered_tools: RegisteredTools, pub doc_link_resolutions: FxHashMap<LocalDefId, DocLinkResMap>, pub doc_link_traits_in_scope: FxHashMap<LocalDefId, Vec<DefId>>, + pub all_macro_rules: FxHashMap<Symbol, Res<ast::NodeId>>, } /// Resolutions that should only be used for lowering. diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index cd9d85b1d91..49eff41329c 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -284,7 +284,7 @@ impl<'a> Parser<'a> { self.sess.source_map().span_to_snippet(span) } - pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + pub(super) fn expected_ident_found(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let valid_follow = &[ TokenKind::Eq, TokenKind::Colon, @@ -324,7 +324,61 @@ impl<'a> Parser<'a> { suggest_raw, suggest_remove_comma, }; - err.into_diagnostic(&self.sess.span_diagnostic) + let mut err = err.into_diagnostic(&self.sess.span_diagnostic); + + // if the token we have is a `<` + // it *might* be a misplaced generic + if self.token == token::Lt { + // all keywords that could have generic applied + let valid_prev_keywords = + [kw::Fn, kw::Type, kw::Struct, kw::Enum, kw::Union, kw::Trait]; + + // If we've expected an identifier, + // and the current token is a '<' + // if the previous token is a valid keyword + // that might use a generic, then suggest a correct + // generic placement (later on) + let maybe_keyword = self.prev_token.clone(); + if valid_prev_keywords.into_iter().any(|x| maybe_keyword.is_keyword(x)) { + // if we have a valid keyword, attempt to parse generics + // also obtain the keywords symbol + match self.parse_generics() { + Ok(generic) => { + if let TokenKind::Ident(symbol, _) = maybe_keyword.kind { + let ident_name = symbol; + // at this point, we've found something like + // `fn <T>id` + // and current token should be Ident with the item name (i.e. the function name) + // if there is a `<` after the fn name, then don't show a suggestion, show help + + if !self.look_ahead(1, |t| *t == token::Lt) && + let Ok(snippet) = self.sess.source_map().span_to_snippet(generic.span) { + err.multipart_suggestion_verbose( + format!("place the generic parameter name after the {ident_name} name"), + vec![ + (self.token.span.shrink_to_hi(), snippet), + (generic.span, String::new()) + ], + Applicability::MaybeIncorrect, + ); + } else { + err.help(format!( + "place the generic parameter name after the {ident_name} name" + )); + } + } + } + Err(err) => { + // if there's an error parsing the generics, + // then don't do a misplaced generics suggestion + // and emit the expected ident error instead; + err.cancel(); + } + } + } + } + + err } pub(super) fn expected_one_of_not_found( diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index e74bb0a9a4f..44f3bf1be05 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1251,6 +1251,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { }; let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas); self.r.set_binding_parent_module(binding, parent_scope.module); + self.r.all_macro_rules.insert(ident.name, res); if is_macro_export { let import = self.r.arenas.alloc_import(Import { kind: ImportKind::MacroExport, diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index b8efa3f8b27..ab68f25a886 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -29,7 +29,7 @@ impl ParentId<'_> { } } -pub struct EffectiveVisibilitiesVisitor<'r, 'a> { +pub(crate) struct EffectiveVisibilitiesVisitor<'r, 'a> { r: &'r mut Resolver<'a>, def_effective_visibilities: EffectiveVisibilities, /// While walking import chains we need to track effective visibilities per-binding, and def id @@ -78,7 +78,7 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> { /// Fills the `Resolver::effective_visibilities` table with public & exported items /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we /// need access to a TyCtxt for that. - pub fn compute_effective_visibilities<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) { + pub(crate) fn compute_effective_visibilities<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) { let mut visitor = EffectiveVisibilitiesVisitor { r, def_effective_visibilities: Default::default(), diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 00f65ac37b6..8d1c789dea7 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -33,7 +33,7 @@ type Res = def::Res<NodeId>; /// Contains data for specific kinds of imports. #[derive(Clone)] -pub enum ImportKind<'a> { +pub(crate) enum ImportKind<'a> { Single { /// `source` in `use prefix::source as target`. source: Ident, @@ -157,11 +157,11 @@ pub(crate) struct Import<'a> { } impl<'a> Import<'a> { - pub fn is_glob(&self) -> bool { + pub(crate) fn is_glob(&self) -> bool { matches!(self.kind, ImportKind::Glob { .. }) } - pub fn is_nested(&self) -> bool { + pub(crate) fn is_nested(&self) -> bool { match self.kind { ImportKind::Single { nested, .. } => nested, _ => false, @@ -405,7 +405,7 @@ struct UnresolvedImportError { candidates: Option<Vec<ImportSuggestion>>, } -pub struct ImportResolver<'a, 'b> { +pub(crate) struct ImportResolver<'a, 'b> { pub r: &'a mut Resolver<'b>, } @@ -420,7 +420,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// Resolves all imports for the crate. This method performs the fixed- /// point iteration. - pub fn resolve_imports(&mut self) { + pub(crate) fn resolve_imports(&mut self) { let mut prev_num_indeterminates = self.r.indeterminate_imports.len() + 1; while self.r.indeterminate_imports.len() < prev_num_indeterminates { prev_num_indeterminates = self.r.indeterminate_imports.len(); @@ -433,7 +433,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } } - pub fn finalize_imports(&mut self) { + pub(crate) fn finalize_imports(&mut self) { for module in self.r.arenas.local_modules().iter() { self.finalize_resolutions_in(module); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index bd74a010fa3..d4c056f12f6 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -56,7 +56,7 @@ struct BindingInfo { } #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum PatternSource { +pub(crate) enum PatternSource { Match, Let, For, @@ -70,7 +70,7 @@ enum IsRepeatExpr { } impl PatternSource { - pub fn descr(self) -> &'static str { + fn descr(self) -> &'static str { match self { PatternSource::Match => "match binding", PatternSource::Let => "let binding", @@ -2374,9 +2374,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Maintain macro_rules scopes in the same way as during early resolution // for diagnostics and doc links. if macro_def.macro_rules { - let (macro_rules_scope, _) = - self.r.macro_rules_scope(self.r.local_def_id(item.id)); - self.parent_scope.macro_rules = macro_rules_scope; + let def_id = self.r.local_def_id(item.id); + self.parent_scope.macro_rules = self.r.macro_rules_scopes[&def_id]; } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index a9dbb3ca131..c6d27ec69c5 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2626,7 +2626,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } /// Report lifetime/lifetime shadowing as an error. -pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) { +pub(super) fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) { let mut err = struct_span_err!( sess, shadower.span, @@ -2641,7 +2641,7 @@ pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) { /// Shadowing involving a label is only a warning for historical reasons. //FIXME: make this a proper lint. -pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) { +pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) { let name = shadower.name; let shadower = shadower.span; let mut err = sess.struct_span_warn( diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index e61e83189c3..3c70e9c93e3 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -21,8 +21,6 @@ #[macro_use] extern crate tracing; -pub use rustc_hir::def::{Namespace, PerNS}; - use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::node_id::NodeMap; use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID}; @@ -32,8 +30,8 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::{Lrc, RwLock}; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind}; -use rustc_hir::def::Namespace::*; -use rustc_hir::def::{self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, PartialRes}; +use rustc_hir::def::Namespace::{self, *}; +use rustc_hir::def::{self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, PartialRes, PerNS}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::{DefPathData, Definitions}; @@ -86,7 +84,7 @@ enum Weak { } #[derive(Copy, Clone, PartialEq, Debug)] -pub enum Determinacy { +enum Determinacy { Determined, Undetermined, } @@ -257,7 +255,7 @@ enum VisResolutionError<'a> { /// A minimal representation of a path segment. We use this in resolve because we synthesize 'path /// segments' which don't have the rest of an AST or HIR `PathSegment`. #[derive(Clone, Copy, Debug)] -pub struct Segment { +struct Segment { ident: Ident, id: Option<NodeId>, /// Signals whether this `PathSegment` has generic arguments. Used to avoid providing @@ -380,7 +378,7 @@ impl ModuleOrUniformRoot<'_> { } } -#[derive(Clone, Debug)] +#[derive(Debug)] enum PathResult<'a> { Module(ModuleOrUniformRoot<'a>), NonModule(PartialRes), @@ -435,7 +433,7 @@ enum ModuleKind { impl ModuleKind { /// Get name of the module. - pub fn name(&self) -> Option<Symbol> { + fn name(&self) -> Option<Symbol> { match self { ModuleKind::Block => None, ModuleKind::Def(.., name) => Some(*name), @@ -471,7 +469,7 @@ type Resolutions<'a> = RefCell<FxIndexMap<BindingKey, &'a RefCell<NameResolution /// * curly-braced block with statements /// /// You can use [`ModuleData::kind`] to determine the kind of module this is. -pub struct ModuleData<'a> { +struct ModuleData<'a> { /// The direct parent module (it may not be a `mod`, however). parent: Option<Module<'a>>, /// What kind of module this is, because this may not be a `mod`. @@ -570,7 +568,7 @@ impl<'a> ModuleData<'a> { } // Public for rustdoc. - pub fn def_id(&self) -> DefId { + fn def_id(&self) -> DefId { self.opt_def_id().expect("`ModuleData::def_id` is called on a block module") } @@ -628,7 +626,7 @@ impl<'a> fmt::Debug for ModuleData<'a> { /// Records a possibly-private value, type, or module definition. #[derive(Clone, Debug)] -pub struct NameBinding<'a> { +struct NameBinding<'a> { kind: NameBindingKind<'a>, ambiguity: Option<(&'a NameBinding<'a>, AmbiguityKind)>, expansion: LocalExpnId, @@ -636,7 +634,7 @@ pub struct NameBinding<'a> { vis: ty::Visibility<DefId>, } -pub trait ToNameBinding<'a> { +trait ToNameBinding<'a> { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a>; } @@ -840,9 +838,9 @@ impl<'a> NameBinding<'a> { } #[derive(Default, Clone)] -pub struct ExternPreludeEntry<'a> { +struct ExternPreludeEntry<'a> { extern_crate_item: Option<&'a NameBinding<'a>>, - pub introduced_by_item: bool, + introduced_by_item: bool, } /// Used for better errors for E0773 @@ -1049,6 +1047,7 @@ pub struct Resolver<'a> { effective_visibilities: EffectiveVisibilities, doc_link_resolutions: FxHashMap<LocalDefId, DocLinkResMap>, doc_link_traits_in_scope: FxHashMap<LocalDefId, Vec<DefId>>, + all_macro_rules: FxHashMap<Symbol, Res>, } /// Nothing really interesting here; it just provides memory for the rest of the crate. @@ -1147,7 +1146,7 @@ impl<'a> Resolver<'a> { self.node_id_to_def_id.get(&node).copied() } - pub fn local_def_id(&self, node: NodeId) -> LocalDefId { + fn local_def_id(&self, node: NodeId) -> LocalDefId { self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node)) } @@ -1199,10 +1198,6 @@ impl<'a> Resolver<'a> { self.cstore().item_generics_num_lifetimes(def_id, self.session) } } - - pub fn sess(&self) -> &'a Session { - self.session - } } impl<'a> Resolver<'a> { @@ -1379,6 +1374,7 @@ impl<'a> Resolver<'a> { effective_visibilities: Default::default(), doc_link_resolutions: Default::default(), doc_link_traits_in_scope: Default::default(), + all_macro_rules: Default::default(), }; let root_parent_scope = ParentScope::module(graph_root, &resolver); @@ -1399,14 +1395,14 @@ impl<'a> Resolver<'a> { self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude, module_map) } - pub fn next_node_id(&mut self) -> NodeId { + fn next_node_id(&mut self) -> NodeId { let start = self.next_node_id; let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds"); self.next_node_id = ast::NodeId::from_u32(next); start } - pub fn next_node_ids(&mut self, count: usize) -> std::ops::Range<NodeId> { + fn next_node_ids(&mut self, count: usize) -> std::ops::Range<NodeId> { let start = self.next_node_id; let end = start.as_usize().checked_add(count).expect("input too large; ran out of NodeIds"); self.next_node_id = ast::NodeId::from_usize(end); @@ -1457,6 +1453,7 @@ impl<'a> Resolver<'a> { registered_tools: self.registered_tools, doc_link_resolutions: self.doc_link_resolutions, doc_link_traits_in_scope: self.doc_link_traits_in_scope, + all_macro_rules: self.all_macro_rules, }; let ast_lowering = ty::ResolverAstLowering { legacy_const_generic_args: self.legacy_const_generic_args, @@ -1475,57 +1472,11 @@ impl<'a> Resolver<'a> { ResolverOutputs { global_ctxt, ast_lowering, untracked } } - pub fn clone_outputs(&self) -> ResolverOutputs { - let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect(); - let definitions = self.untracked.definitions.clone(); - let cstore = Box::new(self.cstore().clone()); - let untracked = - Untracked { cstore, source_span: self.untracked.source_span.clone(), definitions }; - let global_ctxt = ResolverGlobalCtxt { - expn_that_defined: self.expn_that_defined.clone(), - visibilities: self.visibilities.clone(), - has_pub_restricted: self.has_pub_restricted, - extern_crate_map: self.extern_crate_map.clone(), - reexport_map: self.reexport_map.clone(), - glob_map: self.glob_map.clone(), - maybe_unused_trait_imports: self.maybe_unused_trait_imports.clone(), - maybe_unused_extern_crates: self.maybe_unused_extern_crates.clone(), - extern_prelude: self - .extern_prelude - .iter() - .map(|(ident, entry)| (ident.name, entry.introduced_by_item)) - .collect(), - main_def: self.main_def, - trait_impls: self.trait_impls.clone(), - proc_macros, - confused_type_with_std_module: self.confused_type_with_std_module.clone(), - registered_tools: self.registered_tools.clone(), - effective_visibilities: self.effective_visibilities.clone(), - doc_link_resolutions: self.doc_link_resolutions.clone(), - doc_link_traits_in_scope: self.doc_link_traits_in_scope.clone(), - }; - let ast_lowering = ty::ResolverAstLowering { - legacy_const_generic_args: self.legacy_const_generic_args.clone(), - partial_res_map: self.partial_res_map.clone(), - import_res_map: self.import_res_map.clone(), - label_res_map: self.label_res_map.clone(), - lifetimes_res_map: self.lifetimes_res_map.clone(), - extra_lifetime_params_map: self.extra_lifetime_params_map.clone(), - next_node_id: self.next_node_id, - node_id_to_def_id: self.node_id_to_def_id.clone(), - def_id_to_node_id: self.def_id_to_node_id.clone(), - trait_map: self.trait_map.clone(), - builtin_macro_kinds: self.builtin_macro_kinds.clone(), - lifetime_elision_allowed: self.lifetime_elision_allowed.clone(), - }; - ResolverOutputs { global_ctxt, ast_lowering, untracked } - } - fn create_stable_hashing_context(&self) -> StableHashingContext<'_> { StableHashingContext::new(self.session, &self.untracked) } - pub fn crate_loader(&mut self) -> CrateLoader<'_> { + fn crate_loader(&mut self) -> CrateLoader<'_> { CrateLoader::new( &self.session, &*self.metadata_loader, @@ -1536,7 +1487,7 @@ impl<'a> Resolver<'a> { ) } - pub fn cstore(&self) -> &CStore { + fn cstore(&self) -> &CStore { self.untracked.cstore.as_any().downcast_ref().unwrap() } @@ -1968,24 +1919,15 @@ impl<'a> Resolver<'a> { } } - /// For rustdoc. - pub fn macro_rules_scope(&self, def_id: LocalDefId) -> (MacroRulesScopeRef<'a>, Res) { - let scope = *self.macro_rules_scopes.get(&def_id).expect("not a `macro_rules` item"); - match scope.get() { - MacroRulesScope::Binding(mb) => (scope, mb.binding.res()), - _ => unreachable!(), - } - } - /// Retrieves the span of the given `DefId` if `DefId` is in the local crate. #[inline] - pub fn opt_span(&self, def_id: DefId) -> Option<Span> { + fn opt_span(&self, def_id: DefId) -> Option<Span> { def_id.as_local().map(|def_id| self.untracked.source_span[def_id]) } /// Retrieves the name of the given `DefId`. #[inline] - pub fn opt_name(&self, def_id: DefId) -> Option<Symbol> { + fn opt_name(&self, def_id: DefId) -> Option<Symbol> { let def_key = match def_id.as_local() { Some(def_id) => self.untracked.definitions.read().def_key(def_id), None => self.cstore().def_key(def_id), @@ -1996,7 +1938,7 @@ impl<'a> Resolver<'a> { /// Checks if an expression refers to a function marked with /// `#[rustc_legacy_const_generics]` and returns the argument index list /// from the attribute. - pub fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>> { + fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>> { if let ExprKind::Path(None, path) = &expr.kind { // Don't perform legacy const generics rewriting if the path already // has generic arguments. diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 0c2e8be0498..96ad6e96fac 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -39,7 +39,7 @@ type Res = def::Res<NodeId>; /// Binding produced by a `macro_rules` item. /// Not modularized, can shadow previous `macro_rules` bindings, etc. #[derive(Debug)] -pub struct MacroRulesBinding<'a> { +pub(crate) struct MacroRulesBinding<'a> { pub(crate) binding: &'a NameBinding<'a>, /// `macro_rules` scope into which the `macro_rules` item was planted. pub(crate) parent_macro_rules_scope: MacroRulesScopeRef<'a>, @@ -52,7 +52,7 @@ pub struct MacroRulesBinding<'a> { /// Some macro invocations need to introduce `macro_rules` scopes too because they /// can potentially expand into macro definitions. #[derive(Copy, Clone, Debug)] -pub enum MacroRulesScope<'a> { +pub(crate) enum MacroRulesScope<'a> { /// Empty "root" scope at the crate start containing no names. Empty, /// The scope introduced by a `macro_rules!` macro definition. diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index e56588c58bd..32fcd751b46 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -31,6 +31,7 @@ use rustc_middle::ty::{ }; use rustc_span::DUMMY_SP; +use crate::solve::search_graph::OverflowHandler; use crate::traits::ObligationCause; mod assembly; @@ -210,27 +211,16 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { search_graph: &'a mut search_graph::SearchGraph<'tcx>, canonical_goal: CanonicalGoal<'tcx>, ) -> QueryResult<'tcx> { - match search_graph.try_push_stack(tcx, canonical_goal) { - Ok(()) => {} - // Our goal is already on the stack, eager return. - Err(response) => return response, - } - - // We may have to repeatedly recompute the goal in case of coinductive cycles, - // check out the `cache` module for more information. + // Deal with overflow, caching, and coinduction. // - // FIXME: Similar to `evaluate_all`, this has to check for overflow. - loop { + // The actual solver logic happens in `ecx.compute_goal`. + search_graph.with_new_goal(tcx, canonical_goal, |search_graph| { let (ref infcx, goal, var_values) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal); let mut ecx = EvalCtxt { infcx, var_values, search_graph, in_projection_eq_hack: false }; - let result = ecx.compute_goal(goal); - - if search_graph.try_finalize_goal(tcx, canonical_goal, result) { - return result; - } - } + ecx.compute_goal(goal) + }) } fn make_canonical_response(&self, certainty: Certainty) -> QueryResult<'tcx> { @@ -485,35 +475,38 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { mut goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>, ) -> Result<Certainty, NoSolution> { let mut new_goals = Vec::new(); - self.repeat_while_none(|this| { - let mut has_changed = Err(Certainty::Yes); - for goal in goals.drain(..) { - let (changed, certainty) = match this.evaluate_goal(goal) { - Ok(result) => result, - Err(NoSolution) => return Some(Err(NoSolution)), - }; - - if changed { - has_changed = Ok(()); - } + self.repeat_while_none( + |_| Ok(Certainty::Maybe(MaybeCause::Overflow)), + |this| { + let mut has_changed = Err(Certainty::Yes); + for goal in goals.drain(..) { + let (changed, certainty) = match this.evaluate_goal(goal) { + Ok(result) => result, + Err(NoSolution) => return Some(Err(NoSolution)), + }; + + if changed { + has_changed = Ok(()); + } - match certainty { - Certainty::Yes => {} - Certainty::Maybe(_) => { - new_goals.push(goal); - has_changed = has_changed.map_err(|c| c.unify_and(certainty)); + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => { + new_goals.push(goal); + has_changed = has_changed.map_err(|c| c.unify_and(certainty)); + } } } - } - match has_changed { - Ok(()) => { - mem::swap(&mut new_goals, &mut goals); - None + match has_changed { + Ok(()) => { + mem::swap(&mut new_goals, &mut goals); + None + } + Err(certainty) => Some(Ok(certainty)), } - Err(certainty) => Some(Ok(certainty)), - } - }) + }, + ) } // Recursively evaluates a list of goals to completion, making a query response. diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index a2ca4bc189c..e9945cde5df 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -3,6 +3,7 @@ mod overflow; use self::cache::ProvisionalEntry; use super::{CanonicalGoal, Certainty, MaybeCause, QueryResult}; +pub(super) use crate::solve::search_graph::overflow::OverflowHandler; use cache::ProvisionalCache; use overflow::OverflowData; use rustc_index::vec::IndexVec; @@ -46,7 +47,7 @@ impl<'tcx> SearchGraph<'tcx> { /// /// This correctly updates the provisional cache if there is a cycle. #[instrument(level = "debug", skip(self, tcx), ret)] - pub(super) fn try_push_stack( + fn try_push_stack( &mut self, tcx: TyCtxt<'tcx>, goal: CanonicalGoal<'tcx>, @@ -121,19 +122,19 @@ impl<'tcx> SearchGraph<'tcx> { /// /// FIXME: Refer to the rustc-dev-guide entry once it exists. #[instrument(level = "debug", skip(self, tcx, actual_goal), ret)] - pub(super) fn try_finalize_goal( + fn try_finalize_goal( &mut self, tcx: TyCtxt<'tcx>, actual_goal: CanonicalGoal<'tcx>, response: QueryResult<'tcx>, ) -> bool { - let StackElem { goal, has_been_used } = self.stack.pop().unwrap(); + let stack_elem = self.stack.pop().unwrap(); + let StackElem { goal, has_been_used } = stack_elem; assert_eq!(goal, actual_goal); let cache = &mut self.provisional_cache; let provisional_entry_index = *cache.lookup_table.get(&goal).unwrap(); let provisional_entry = &mut cache.entries[provisional_entry_index]; - let depth = provisional_entry.depth; // We eagerly update the response in the cache here. If we have to reevaluate // this goal we use the new response when hitting a cycle, and we definitely // want to access the final response whenever we look at the cache. @@ -157,29 +158,72 @@ impl<'tcx> SearchGraph<'tcx> { self.stack.push(StackElem { goal, has_been_used: false }); false } else { - // If not, we're done with this goal. - // - // Check whether that this goal doesn't depend on a goal deeper on the stack - // and if so, move it and all nested goals to the global cache. - // - // Note that if any nested goal were to depend on something deeper on the stack, - // this would have also updated the depth of the current goal. - if depth == self.stack.next_index() { - for (i, entry) in cache.entries.drain_enumerated(provisional_entry_index.index()..) - { - let actual_index = cache.lookup_table.remove(&entry.goal); - debug_assert_eq!(Some(i), actual_index); - debug_assert!(entry.depth == depth); - cache::try_move_finished_goal_to_global_cache( - tcx, - &mut self.overflow_data, - &self.stack, - entry.goal, - entry.response, - ); - } - } + self.try_move_finished_goal_to_global_cache(tcx, stack_elem); true } } + + fn try_move_finished_goal_to_global_cache( + &mut self, + tcx: TyCtxt<'tcx>, + stack_elem: StackElem<'tcx>, + ) { + let StackElem { goal, .. } = stack_elem; + let cache = &mut self.provisional_cache; + let provisional_entry_index = *cache.lookup_table.get(&goal).unwrap(); + let provisional_entry = &mut cache.entries[provisional_entry_index]; + let depth = provisional_entry.depth; + + // If not, we're done with this goal. + // + // Check whether that this goal doesn't depend on a goal deeper on the stack + // and if so, move it and all nested goals to the global cache. + // + // Note that if any nested goal were to depend on something deeper on the stack, + // this would have also updated the depth of the current goal. + if depth == self.stack.next_index() { + for (i, entry) in cache.entries.drain_enumerated(provisional_entry_index.index()..) { + let actual_index = cache.lookup_table.remove(&entry.goal); + debug_assert_eq!(Some(i), actual_index); + debug_assert!(entry.depth == depth); + cache::try_move_finished_goal_to_global_cache( + tcx, + &mut self.overflow_data, + &self.stack, + entry.goal, + entry.response, + ); + } + } + } + + pub(super) fn with_new_goal( + &mut self, + tcx: TyCtxt<'tcx>, + canonical_goal: CanonicalGoal<'tcx>, + mut loop_body: impl FnMut(&mut Self) -> QueryResult<'tcx>, + ) -> QueryResult<'tcx> { + match self.try_push_stack(tcx, canonical_goal) { + Ok(()) => {} + // Our goal is already on the stack, eager return. + Err(response) => return response, + } + + self.repeat_while_none( + |this| { + let result = this.deal_with_overflow(tcx, canonical_goal); + let stack_elem = this.stack.pop().unwrap(); + this.try_move_finished_goal_to_global_cache(tcx, stack_elem); + result + }, + |this| { + let result = loop_body(this); + if this.try_finalize_goal(tcx, canonical_goal, result) { + Some(result) + } else { + None + } + }, + ) + } } diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs b/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs index 1dd3894c91a..56409b0602b 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs @@ -50,6 +50,42 @@ impl OverflowData { } } +pub(in crate::solve) trait OverflowHandler<'tcx> { + fn search_graph(&mut self) -> &mut SearchGraph<'tcx>; + + fn repeat_while_none<T>( + &mut self, + on_overflow: impl FnOnce(&mut Self) -> Result<T, NoSolution>, + mut loop_body: impl FnMut(&mut Self) -> Option<Result<T, NoSolution>>, + ) -> Result<T, NoSolution> { + let start_depth = self.search_graph().overflow_data.additional_depth; + let depth = self.search_graph().stack.len(); + while !self.search_graph().overflow_data.has_overflow(depth) { + if let Some(result) = loop_body(self) { + self.search_graph().overflow_data.additional_depth = start_depth; + return result; + } + + self.search_graph().overflow_data.additional_depth += 1; + } + self.search_graph().overflow_data.additional_depth = start_depth; + self.search_graph().overflow_data.deal_with_overflow(); + on_overflow(self) + } +} + +impl<'tcx> OverflowHandler<'tcx> for EvalCtxt<'_, 'tcx> { + fn search_graph(&mut self) -> &mut SearchGraph<'tcx> { + &mut self.search_graph + } +} + +impl<'tcx> OverflowHandler<'tcx> for SearchGraph<'tcx> { + fn search_graph(&mut self) -> &mut SearchGraph<'tcx> { + self + } +} + impl<'tcx> SearchGraph<'tcx> { pub fn deal_with_overflow( &mut self, @@ -60,25 +96,3 @@ impl<'tcx> SearchGraph<'tcx> { response_no_constraints(tcx, goal, Certainty::Maybe(MaybeCause::Overflow)) } } - -impl<'tcx> EvalCtxt<'_, 'tcx> { - /// A `while`-loop which tracks overflow. - pub fn repeat_while_none( - &mut self, - mut loop_body: impl FnMut(&mut Self) -> Option<Result<Certainty, NoSolution>>, - ) -> Result<Certainty, NoSolution> { - let start_depth = self.search_graph.overflow_data.additional_depth; - let depth = self.search_graph.stack.len(); - while !self.search_graph.overflow_data.has_overflow(depth) { - if let Some(result) = loop_body(self) { - self.search_graph.overflow_data.additional_depth = start_depth; - return result; - } - - self.search_graph.overflow_data.additional_depth += 1; - } - self.search_graph.overflow_data.additional_depth = start_depth; - self.search_graph.overflow_data.deal_with_overflow(); - Ok(Certainty::Maybe(MaybeCause::Overflow)) - } -} diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 302adb79766..fc9678233c3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -27,6 +27,7 @@ use super::{ use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::traits::error_reporting::TypeErrCtxtExt; +use crate::traits::project::try_normalize_with_depth_to; use crate::traits::project::ProjectAndUnifyResult; use crate::traits::project::ProjectionCacheKeyExt; use crate::traits::ProjectionCacheKey; @@ -1049,7 +1050,51 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Ok(cycle_result); } - let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack)); + let (result, dep_node) = self.in_task(|this| { + let mut result = this.evaluate_stack(&stack)?; + + // fix issue #103563, we don't normalize + // nested obligations which produced by `TraitDef` candidate + // (i.e. using bounds on assoc items as assumptions). + // because we don't have enough information to + // normalize these obligations before evaluating. + // so we will try to normalize the obligation and evaluate again. + // we will replace it with new solver in the future. + if EvaluationResult::EvaluatedToErr == result + && fresh_trait_pred.has_projections() + && fresh_trait_pred.is_global() + { + let mut nested_obligations = Vec::new(); + let predicate = try_normalize_with_depth_to( + this, + param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.predicate, + &mut nested_obligations, + ); + if predicate != obligation.predicate { + let mut nested_result = EvaluationResult::EvaluatedToOk; + for obligation in nested_obligations { + nested_result = cmp::max( + this.evaluate_predicate_recursively(stack.list(), obligation)?, + nested_result, + ); + } + + if nested_result.must_apply_modulo_regions() { + let obligation = obligation.with(this.tcx(), predicate); + result = cmp::max( + nested_result, + this.evaluate_trait_predicate_recursively(stack.list(), obligation)?, + ); + } + } + } + + Ok::<_, OverflowError>(result) + }); + let result = result?; if !result.must_apply_modulo_regions() { diff --git a/library/core/benches/array.rs b/library/core/benches/array.rs index 845c6076294..d8cc44d05c4 100644 --- a/library/core/benches/array.rs +++ b/library/core/benches/array.rs @@ -11,9 +11,9 @@ macro_rules! map_array { }; } -map_array!(map_8byte_8byte_8, 0u64, 1u64, 800); -map_array!(map_8byte_8byte_64, 0u64, 1u64, 6400); -map_array!(map_8byte_8byte_256, 0u64, 1u64, 25600); +map_array!(map_8byte_8byte_8, 0u64, 1u64, 80); +map_array!(map_8byte_8byte_64, 0u64, 1u64, 640); +map_array!(map_8byte_8byte_256, 0u64, 1u64, 2560); -map_array!(map_8byte_256byte_256, 0u64, [0u64; 4], 25600); -map_array!(map_256byte_8byte_256, [0u64; 4], 0u64, 25600); +map_array!(map_8byte_256byte_256, 0u64, [0u64; 4], 2560); +map_array!(map_256byte_8byte_256, [0u64; 4], 0u64, 2560); diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 16eb726f6f6..57e2ffe5d20 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -23,8 +23,6 @@ impl<T: ?Sized> *const T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s: &str = "Follow the rabbit"; /// let ptr: *const u8 = s.as_ptr(); @@ -323,8 +321,6 @@ impl<T: ?Sized> *const T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let ptr: *const u8 = &10u8 as *const u8; /// @@ -384,8 +380,6 @@ impl<T: ?Sized> *const T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(ptr_as_uninit)] /// @@ -449,8 +443,6 @@ impl<T: ?Sized> *const T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s: &str = "123"; /// let ptr: *const u8 = s.as_ptr(); @@ -526,8 +518,6 @@ impl<T: ?Sized> *const T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// // Iterate using a raw pointer in increments of two elements /// let data = [1u8, 2, 3, 4, 5]; @@ -908,8 +898,6 @@ impl<T: ?Sized> *const T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s: &str = "123"; /// let ptr: *const u8 = s.as_ptr(); @@ -993,8 +981,6 @@ impl<T: ?Sized> *const T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s: &str = "123"; /// @@ -1072,8 +1058,6 @@ impl<T: ?Sized> *const T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// // Iterate using a raw pointer in increments of two elements /// let data = [1u8, 2, 3, 4, 5]; @@ -1152,8 +1136,6 @@ impl<T: ?Sized> *const T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// // Iterate using a raw pointer in increments of two elements (backwards) /// let data = [1u8, 2, 3, 4, 5]; @@ -1359,7 +1341,6 @@ impl<T: ?Sized> *const T { /// /// # Examples /// - /// Basic usage: /// ``` /// #![feature(pointer_is_aligned)] /// #![feature(pointer_byte_offsets)] @@ -1482,7 +1463,6 @@ impl<T: ?Sized> *const T { /// /// # Examples /// - /// Basic usage: /// ``` /// #![feature(pointer_is_aligned)] /// #![feature(pointer_byte_offsets)] diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 0a2f63e3ec6..422d0f2b8f0 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -22,8 +22,6 @@ impl<T: ?Sized> *mut T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = [1, 2, 3]; /// let ptr: *mut u32 = s.as_mut_ptr(); @@ -332,8 +330,6 @@ impl<T: ?Sized> *mut T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let ptr: *mut u8 = &mut 10u8 as *mut u8; /// @@ -396,8 +392,6 @@ impl<T: ?Sized> *mut T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(ptr_as_uninit)] /// @@ -461,8 +455,6 @@ impl<T: ?Sized> *mut T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = [1, 2, 3]; /// let ptr: *mut u32 = s.as_mut_ptr(); @@ -539,8 +531,6 @@ impl<T: ?Sized> *mut T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// // Iterate using a raw pointer in increments of two elements /// let mut data = [1u8, 2, 3, 4, 5]; @@ -660,8 +650,6 @@ impl<T: ?Sized> *mut T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut s = [1, 2, 3]; /// let ptr: *mut u32 = s.as_mut_ptr(); @@ -1010,8 +998,6 @@ impl<T: ?Sized> *mut T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s: &str = "123"; /// let ptr: *const u8 = s.as_ptr(); @@ -1095,8 +1081,6 @@ impl<T: ?Sized> *mut T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s: &str = "123"; /// @@ -1174,8 +1158,6 @@ impl<T: ?Sized> *mut T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// // Iterate using a raw pointer in increments of two elements /// let data = [1u8, 2, 3, 4, 5]; @@ -1254,8 +1236,6 @@ impl<T: ?Sized> *mut T { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// // Iterate using a raw pointer in increments of two elements (backwards) /// let data = [1u8, 2, 3, 4, 5]; @@ -1627,7 +1607,6 @@ impl<T: ?Sized> *mut T { /// /// # Examples /// - /// Basic usage: /// ``` /// #![feature(pointer_is_aligned)] /// #![feature(pointer_byte_offsets)] @@ -1752,7 +1731,6 @@ impl<T: ?Sized> *mut T { /// /// # Examples /// - /// Basic usage: /// ``` /// #![feature(pointer_is_aligned)] /// #![feature(pointer_byte_offsets)] diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index ffe6fea7ea4..b00cefdddb5 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -482,16 +482,16 @@ impl Item { } pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> { - use crate::html::format::href; + use crate::html::format::{href, link_tooltip}; cx.cache() .intra_doc_links .get(&self.item_id) .map_or(&[][..], |v| v.as_slice()) .iter() - .filter_map(|ItemLink { link: s, link_text, page_id: did, ref fragment }| { - debug!(?did); - if let Ok((mut href, ..)) = href(*did, cx) { + .filter_map(|ItemLink { link: s, link_text, page_id: id, ref fragment }| { + debug!(?id); + if let Ok((mut href, ..)) = href(*id, cx) { debug!(?href); if let Some(ref fragment) = *fragment { fragment.render(&mut href, cx.tcx()) @@ -499,6 +499,7 @@ impl Item { Some(RenderedLink { original_text: s.clone(), new_text: link_text.clone(), + tooltip: link_tooltip(*id, fragment, cx), href, }) } else { @@ -523,6 +524,7 @@ impl Item { original_text: s.clone(), new_text: link_text.clone(), href: String::new(), + tooltip: String::new(), }) .collect() } @@ -1040,6 +1042,8 @@ pub struct RenderedLink { pub(crate) new_text: String, /// The URL to put in the `href` pub(crate) href: String, + /// The tooltip. + pub(crate) tooltip: String, } /// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 7e16c4701be..5ab7056be44 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -1,4 +1,3 @@ -use rustc_ast::NodeId; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{self, Lrc}; use rustc_data_structures::unord::UnordSet; @@ -17,7 +16,7 @@ use rustc_session::config::{self, CrateType, ErrorOutputType, ResolveDocLinks}; use rustc_session::lint; use rustc_session::Session; use rustc_span::symbol::sym; -use rustc_span::{source_map, Span, Symbol}; +use rustc_span::{source_map, Span}; use std::cell::RefCell; use std::mem; @@ -32,15 +31,8 @@ use crate::passes::{self, Condition::*}; pub(crate) use rustc_session::config::{Input, Options, UnstableOptions}; -pub(crate) struct ResolverCaches { - pub(crate) all_trait_impls: Option<Vec<DefId>>, - pub(crate) all_macro_rules: FxHashMap<Symbol, Res<NodeId>>, - pub(crate) extern_doc_reachable: DefIdSet, -} - pub(crate) struct DocContext<'tcx> { pub(crate) tcx: TyCtxt<'tcx>, - pub(crate) resolver_caches: ResolverCaches, /// Used for normalization. /// /// Most of this logic is copied from rustc_lint::late. @@ -111,12 +103,6 @@ impl<'tcx> DocContext<'tcx> { _ => None, } } - - pub(crate) fn with_all_trait_impls(&mut self, f: impl FnOnce(&mut Self, &[DefId])) { - let all_trait_impls = self.resolver_caches.all_trait_impls.take(); - f(self, all_trait_impls.as_ref().expect("`all_trait_impls` are already borrowed")); - self.resolver_caches.all_trait_impls = all_trait_impls; - } } /// Creates a new diagnostic `Handler` that can be used to emit warnings and errors. @@ -305,7 +291,6 @@ pub(crate) fn create_config( pub(crate) fn run_global_ctxt( tcx: TyCtxt<'_>, - resolver_caches: ResolverCaches, show_coverage: bool, render_options: RenderOptions, output_format: OutputFormat, @@ -339,7 +324,6 @@ pub(crate) fn run_global_ctxt( let mut ctxt = DocContext { tcx, - resolver_caches, param_env: ParamEnv::empty(), external_traits: Default::default(), active_extern_traits: Default::default(), @@ -354,9 +338,9 @@ pub(crate) fn run_global_ctxt( show_coverage, }; - ctxt.cache - .effective_visibilities - .init(mem::take(&mut ctxt.resolver_caches.extern_doc_reachable)); + for cnum in tcx.crates(()) { + crate::visit_lib::lib_embargo_visit_item(&mut ctxt, cnum.as_def_id()); + } // Small hack to force the Sized trait to be present. // diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 8a7a8ea5fd1..314f0612249 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -34,6 +34,7 @@ use crate::clean::{ use crate::formats::item_type::ItemType; use crate::html::escape::Escape; use crate::html::render::Context; +use crate::passes::collect_intra_doc_links::UrlFragment; use super::url_parts_builder::estimate_item_path_byte_length; use super::url_parts_builder::UrlPartsBuilder; @@ -768,6 +769,21 @@ pub(crate) fn href_relative_parts<'fqp>( } } +pub(crate) fn link_tooltip(did: DefId, fragment: &Option<UrlFragment>, cx: &Context<'_>) -> String { + let cache = cx.cache(); + let Some((fqp, shortty)) = cache.paths.get(&did) + .or_else(|| cache.external_paths.get(&did)) + else { return String::new() }; + let fqp = fqp.iter().map(|sym| sym.as_str()).join("::"); + if let &Some(UrlFragment::Item(id)) = fragment { + let name = cx.tcx().item_name(id); + let descr = cx.tcx().def_kind(id).descr(id); + format!("{descr} {fqp}::{name}") + } else { + format!("{shortty} {fqp}") + } +} + /// Used to render a [`clean::Path`]. fn resolved_path<'cx>( w: &mut fmt::Formatter<'_>, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 33180439393..e4adee6ae4d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -360,6 +360,9 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> { trace!("it matched"); assert!(self.shortcut_link.is_none(), "shortcut links cannot be nested"); self.shortcut_link = Some(link); + if title.is_empty() && !link.tooltip.is_empty() { + *title = CowStr::Borrowed(link.tooltip.as_ref()); + } } } // Now that we're done with the shortcut link, don't replace any more text. @@ -410,9 +413,12 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for LinkReplacer<'a, I> { } // If this is a link, but not a shortcut link, // replace the URL, since the broken_link_callback was not called. - Some(Event::Start(Tag::Link(_, dest, _))) => { + Some(Event::Start(Tag::Link(_, dest, title))) => { if let Some(link) = self.links.iter().find(|&link| *link.original_text == **dest) { *dest = CowStr::Borrowed(link.href.as_ref()); + if title.is_empty() && !link.tooltip.is_empty() { + *title = CowStr::Borrowed(link.tooltip.as_ref()); + } } } // Anything else couldn't have been a valid Rust path, so no need to replace the text. @@ -976,7 +982,7 @@ impl Markdown<'_> { links .iter() .find(|link| link.original_text.as_str() == &*broken_link.reference) - .map(|link| (link.href.as_str().into(), link.new_text.as_str().into())) + .map(|link| (link.href.as_str().into(), link.tooltip.as_str().into())) }; let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut replacer)); @@ -1059,7 +1065,7 @@ impl MarkdownSummaryLine<'_> { links .iter() .find(|link| link.original_text.as_str() == &*broken_link.reference) - .map(|link| (link.href.as_str().into(), link.new_text.as_str().into())) + .map(|link| (link.href.as_str().into(), link.tooltip.as_str().into())) }; let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer)) @@ -1106,7 +1112,7 @@ fn markdown_summary_with_limit( link_names .iter() .find(|link| link.original_text.as_str() == &*broken_link.reference) - .map(|link| (link.href.as_str().into(), link.new_text.as_str().into())) + .map(|link| (link.href.as_str().into(), link.tooltip.as_str().into())) }; let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer)); @@ -1187,7 +1193,7 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin link_names .iter() .find(|link| link.original_text.as_str() == &*broken_link.reference) - .map(|link| (link.href.as_str().into(), link.new_text.as_str().into())) + .map(|link| (link.href.as_str().into(), link.tooltip.as_str().into())) }; let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer)); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index feefb8b69d1..910a7190b58 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -82,7 +82,6 @@ use rustc_session::getopts; use rustc_session::{early_error, early_warn}; use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL; -use crate::passes::collect_intra_doc_links; /// A macro to create a FxHashMap. /// @@ -793,30 +792,14 @@ fn main_args(at_args: &[String]) -> MainResult { } compiler.enter(|queries| { - let resolver_caches = { - let expansion = abort_on_err(queries.expansion(), sess); - let (krate, resolver, _) = &*expansion.borrow(); - let resolver_caches = resolver.borrow_mut().access(|resolver| { - collect_intra_doc_links::early_resolve_intra_doc_links(resolver, krate) - }); - resolver_caches - }; - + let mut gcx = abort_on_err(queries.global_ctxt(), sess); if sess.diagnostic().has_errors_or_lint_errors().is_some() { sess.fatal("Compilation failed, aborting rustdoc"); } - let mut gcx = abort_on_err(queries.global_ctxt(), sess); - gcx.enter(|tcx| { let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || { - core::run_global_ctxt( - tcx, - resolver_caches, - show_coverage, - render_options, - output_format, - ) + core::run_global_ctxt(tcx, show_coverage, render_options, output_format) }); info!("finished with rustc"); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 0e2191185eb..7e3149a59e3 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -24,6 +24,7 @@ use rustc_span::BytePos; use smallvec::{smallvec, SmallVec}; use std::borrow::Cow; +use std::mem; use std::ops::Range; use crate::clean::{self, utils::find_nearest_parent_module}; @@ -34,9 +35,6 @@ use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}; use crate::passes::Pass; use crate::visit::DocVisitor; -mod early; -pub(crate) use early::early_resolve_intra_doc_links; - pub(crate) const COLLECT_INTRA_DOC_LINKS: Pass = Pass { name: "collect-intra-doc-links", run: collect_intra_doc_links, @@ -1616,7 +1614,7 @@ fn resolution_failure( // ignore duplicates let mut variants_seen = SmallVec::<[_; 3]>::new(); for mut failure in kinds { - let variant = std::mem::discriminant(&failure); + let variant = mem::discriminant(&failure); if variants_seen.contains(&variant) { continue; } @@ -1686,7 +1684,7 @@ fn resolution_failure( if !path_str.contains("::") { if disambiguator.map_or(true, |d| d.ns() == MacroNS) - && let Some(&res) = collector.cx.resolver_caches.all_macro_rules + && let Some(&res) = collector.cx.tcx.resolutions(()).all_macro_rules .get(&Symbol::intern(path_str)) { diag.note(format!( diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs deleted file mode 100644 index ec449e94ce5..00000000000 --- a/src/librustdoc/passes/collect_intra_doc_links/early.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::core::ResolverCaches; -use crate::visit_lib::early_lib_embargo_visit_item; - -use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{self as ast, ItemKind}; -use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def::Res; -use rustc_hir::def_id::{DefId, DefIdSet}; -use rustc_resolve::Resolver; -use rustc_span::Symbol; - -pub(crate) fn early_resolve_intra_doc_links( - resolver: &mut Resolver<'_>, - krate: &ast::Crate, -) -> ResolverCaches { - let mut link_resolver = EarlyDocLinkResolver { - resolver, - all_trait_impls: Default::default(), - all_macro_rules: Default::default(), - extern_doc_reachable: Default::default(), - }; - - visit::walk_crate(&mut link_resolver, krate); - link_resolver.process_extern_impls(); - - ResolverCaches { - all_trait_impls: Some(link_resolver.all_trait_impls), - all_macro_rules: link_resolver.all_macro_rules, - extern_doc_reachable: link_resolver.extern_doc_reachable, - } -} - -struct EarlyDocLinkResolver<'r, 'ra> { - resolver: &'r mut Resolver<'ra>, - all_trait_impls: Vec<DefId>, - all_macro_rules: FxHashMap<Symbol, Res<ast::NodeId>>, - /// This set is used as a seed for `effective_visibilities`, which are then extended by some - /// more items using `lib_embargo_visit_item` during doc inlining. - extern_doc_reachable: DefIdSet, -} - -impl<'ra> EarlyDocLinkResolver<'_, 'ra> { - fn process_extern_impls(&mut self) { - for cnum in self.resolver.cstore().crates_untracked() { - early_lib_embargo_visit_item( - self.resolver, - &mut self.extern_doc_reachable, - cnum.as_def_id(), - true, - ); - for (_, impl_def_id, _) in self.resolver.cstore().trait_impls_in_crate_untracked(cnum) { - self.all_trait_impls.push(impl_def_id); - } - } - } -} - -impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> { - fn visit_item(&mut self, item: &ast::Item) { - match &item.kind { - ItemKind::Impl(impl_) if impl_.of_trait.is_some() => { - self.all_trait_impls.push(self.resolver.local_def_id(item.id).to_def_id()); - } - ItemKind::MacroDef(macro_def) if macro_def.macro_rules => { - let (_, res) = self.resolver.macro_rules_scope(self.resolver.local_def_id(item.id)); - self.all_macro_rules.insert(item.ident.name, res); - } - _ => {} - } - visit::walk_item(self, item); - } -} diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 7d15a207d06..878e738fe50 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -45,18 +45,20 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> let mut new_items_local = Vec::new(); // External trait impls. - cx.with_all_trait_impls(|cx, all_trait_impls| { + { let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impls"); - for &impl_def_id in all_trait_impls.iter().skip_while(|def_id| def_id.is_local()) { - inline::build_impl(cx, None, impl_def_id, None, &mut new_items_external); + for &cnum in cx.tcx.crates(()) { + for &impl_def_id in cx.tcx.trait_impls_in_crate(cnum) { + inline::build_impl(cx, None, impl_def_id, None, &mut new_items_external); + } } - }); + } // Local trait impls. - cx.with_all_trait_impls(|cx, all_trait_impls| { + { let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls"); let mut attr_buf = Vec::new(); - for &impl_def_id in all_trait_impls.iter().take_while(|def_id| def_id.is_local()) { + for &impl_def_id in cx.tcx.trait_impls_in_crate(LOCAL_CRATE) { let mut parent = Some(cx.tcx.parent(impl_def_id)); while let Some(did) = parent { attr_buf.extend( @@ -76,7 +78,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items_local); attr_buf.clear(); } - }); + } cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| { for def_id in PrimitiveType::all_impls(cx.tcx) { diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 07d8b78d767..fd4f9254107 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -1,8 +1,7 @@ use crate::core::DocContext; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::TyCtxt; -use rustc_resolve::Resolver; // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses @@ -26,10 +25,6 @@ impl RustdocEffectiveVisibilities { define_method!(is_directly_public); define_method!(is_exported); define_method!(is_reachable); - - pub(crate) fn init(&mut self, extern_public: DefIdSet) { - self.extern_public = extern_public; - } } pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) { @@ -42,17 +37,6 @@ pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) { .visit_item(def_id) } -pub(crate) fn early_lib_embargo_visit_item( - resolver: &Resolver<'_>, - extern_public: &mut DefIdSet, - def_id: DefId, - is_mod: bool, -) { - assert!(!def_id.is_local()); - EarlyLibEmbargoVisitor { resolver, extern_public, visited_mods: Default::default() } - .visit_item(def_id, is_mod) -} - /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes /// specific rustdoc annotations into account (i.e., `doc(hidden)`) struct LibEmbargoVisitor<'a, 'tcx> { @@ -63,14 +47,6 @@ struct LibEmbargoVisitor<'a, 'tcx> { visited_mods: DefIdSet, } -struct EarlyLibEmbargoVisitor<'r, 'ra> { - resolver: &'r Resolver<'ra>, - // Effective visibilities for reachable nodes - extern_public: &'r mut DefIdSet, - // Keeps track of already visited modules, in case a module re-exports its parent - visited_mods: DefIdSet, -} - impl LibEmbargoVisitor<'_, '_> { fn visit_mod(&mut self, def_id: DefId) { if !self.visited_mods.insert(def_id) { @@ -95,28 +71,3 @@ impl LibEmbargoVisitor<'_, '_> { } } } - -impl EarlyLibEmbargoVisitor<'_, '_> { - fn visit_mod(&mut self, def_id: DefId) { - if !self.visited_mods.insert(def_id) { - return; - } - - for item in self.resolver.cstore().module_children_untracked(def_id, self.resolver.sess()) { - if let Some(def_id) = item.res.opt_def_id() { - if item.vis.is_public() { - self.visit_item(def_id, matches!(item.res, Res::Def(DefKind::Mod, _))); - } - } - } - } - - fn visit_item(&mut self, def_id: DefId, is_mod: bool) { - if !self.resolver.cstore().is_doc_hidden_untracked(def_id) { - self.extern_public.insert(def_id); - if is_mod { - self.visit_mod(def_id); - } - } - } -} diff --git a/tests/rustdoc/intra-doc/basic.rs b/tests/rustdoc/intra-doc/basic.rs index 39f5c298bc4..e2d3ef425cb 100644 --- a/tests/rustdoc/intra-doc/basic.rs +++ b/tests/rustdoc/intra-doc/basic.rs @@ -1,21 +1,38 @@ // @has basic/index.html // @has - '//a/@href' 'struct.ThisType.html' +// @has - '//a/@title' 'struct basic::ThisType' // @has - '//a/@href' 'struct.ThisType.html#method.this_method' +// @has - '//a/@title' 'associated function basic::ThisType::this_method' // @has - '//a/@href' 'enum.ThisEnum.html' +// @has - '//a/@title' 'enum basic::ThisEnum' // @has - '//a/@href' 'enum.ThisEnum.html#variant.ThisVariant' +// @has - '//a/@title' 'variant basic::ThisEnum::ThisVariant' // @has - '//a/@href' 'trait.ThisTrait.html' +// @has - '//a/@title' 'trait basic::ThisTrait' // @has - '//a/@href' 'trait.ThisTrait.html#tymethod.this_associated_method' +// @has - '//a/@title' 'associated function basic::ThisTrait::this_associated_method' // @has - '//a/@href' 'trait.ThisTrait.html#associatedtype.ThisAssociatedType' +// @has - '//a/@title' 'associated type basic::ThisTrait::ThisAssociatedType' // @has - '//a/@href' 'trait.ThisTrait.html#associatedconstant.THIS_ASSOCIATED_CONST' +// @has - '//a/@title' 'associated constant basic::ThisTrait::THIS_ASSOCIATED_CONST' // @has - '//a/@href' 'trait.ThisTrait.html' +// @has - '//a/@title' 'trait basic::ThisTrait' // @has - '//a/@href' 'type.ThisAlias.html' +// @has - '//a/@title' 'type basic::ThisAlias' // @has - '//a/@href' 'union.ThisUnion.html' +// @has - '//a/@title' 'union basic::ThisUnion' // @has - '//a/@href' 'fn.this_function.html' +// @has - '//a/@title' 'fn basic::this_function' // @has - '//a/@href' 'constant.THIS_CONST.html' +// @has - '//a/@title' 'constant basic::THIS_CONST' // @has - '//a/@href' 'static.THIS_STATIC.html' +// @has - '//a/@title' 'static basic::THIS_STATIC' // @has - '//a/@href' 'macro.this_macro.html' +// @has - '//a/@title' 'macro basic::this_macro' // @has - '//a/@href' 'trait.SoAmbiguous.html' +// @has - '//a/@title' 'trait basic::SoAmbiguous' // @has - '//a/@href' 'fn.SoAmbiguous.html' +// @has - '//a/@title' 'fn basic::SoAmbiguous' //! In this crate we would like to link to: //! //! * [`ThisType`](ThisType) diff --git a/tests/ui/parser/suggest_misplaced_generics/enum.fixed b/tests/ui/parser/suggest_misplaced_generics/enum.fixed new file mode 100644 index 00000000000..3332118a1e7 --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/enum.fixed @@ -0,0 +1,9 @@ +// Issue: 103366 , Suggest fix for misplaced generic params +// run-rustfix + +#[allow(unused)] +enum Foo<T> { Variant(T) } +//~^ ERROR expected identifier, found `<` +//~| HELP place the generic parameter name after the enum name + +fn main() {} diff --git a/tests/ui/parser/suggest_misplaced_generics/enum.rs b/tests/ui/parser/suggest_misplaced_generics/enum.rs new file mode 100644 index 00000000000..5a2289c5c5a --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/enum.rs @@ -0,0 +1,9 @@ +// Issue: 103366 , Suggest fix for misplaced generic params +// run-rustfix + +#[allow(unused)] +enum<T> Foo { Variant(T) } +//~^ ERROR expected identifier, found `<` +//~| HELP place the generic parameter name after the enum name + +fn main() {} diff --git a/tests/ui/parser/suggest_misplaced_generics/enum.stderr b/tests/ui/parser/suggest_misplaced_generics/enum.stderr new file mode 100644 index 00000000000..5f5947627ee --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/enum.stderr @@ -0,0 +1,14 @@ +error: expected identifier, found `<` + --> $DIR/enum.rs:5:5 + | +LL | enum<T> Foo { Variant(T) } + | ^ expected identifier + | +help: place the generic parameter name after the enum name + | +LL - enum<T> Foo { Variant(T) } +LL + enum Foo<T> { Variant(T) } + | + +error: aborting due to previous error + diff --git a/tests/ui/parser/suggest_misplaced_generics/existing_generics.rs b/tests/ui/parser/suggest_misplaced_generics/existing_generics.rs new file mode 100644 index 00000000000..1dc182398d8 --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/existing_generics.rs @@ -0,0 +1,9 @@ +// Issue: 103366 +// there is already an existing generic on f, so don't show a suggestion + +#[allow(unused)] +fn<'a, B: 'a + std::ops::Add<Output = u32>> f<T>(_x: B) { } +//~^ ERROR expected identifier, found `<` +//~| HELP place the generic parameter name after the fn name + +fn main() {} diff --git a/tests/ui/parser/suggest_misplaced_generics/existing_generics.stderr b/tests/ui/parser/suggest_misplaced_generics/existing_generics.stderr new file mode 100644 index 00000000000..89716e6f1ed --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/existing_generics.stderr @@ -0,0 +1,10 @@ +error: expected identifier, found `<` + --> $DIR/existing_generics.rs:5:3 + | +LL | fn<'a, B: 'a + std::ops::Add<Output = u32>> f<T>(_x: B) { } + | ^ expected identifier + | + = help: place the generic parameter name after the fn name + +error: aborting due to previous error + diff --git a/tests/ui/parser/suggest_misplaced_generics/fn-complex-generics.fixed b/tests/ui/parser/suggest_misplaced_generics/fn-complex-generics.fixed new file mode 100644 index 00000000000..84bf64bd63c --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/fn-complex-generics.fixed @@ -0,0 +1,9 @@ +// Issue: 103366 , Suggest fix for misplaced generic params +// run-rustfix + +#[allow(unused)] +fn f<'a, B: 'a + std::ops::Add<Output = u32>>(_x: B) { } +//~^ ERROR expected identifier, found `<` +//~| HELP place the generic parameter name after the fn name + +fn main() {} diff --git a/tests/ui/parser/suggest_misplaced_generics/fn-complex-generics.rs b/tests/ui/parser/suggest_misplaced_generics/fn-complex-generics.rs new file mode 100644 index 00000000000..d0684397e74 --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/fn-complex-generics.rs @@ -0,0 +1,9 @@ +// Issue: 103366 , Suggest fix for misplaced generic params +// run-rustfix + +#[allow(unused)] +fn<'a, B: 'a + std::ops::Add<Output = u32>> f(_x: B) { } +//~^ ERROR expected identifier, found `<` +//~| HELP place the generic parameter name after the fn name + +fn main() {} diff --git a/tests/ui/parser/suggest_misplaced_generics/fn-complex-generics.stderr b/tests/ui/parser/suggest_misplaced_generics/fn-complex-generics.stderr new file mode 100644 index 00000000000..061d0910a74 --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/fn-complex-generics.stderr @@ -0,0 +1,14 @@ +error: expected identifier, found `<` + --> $DIR/fn-complex-generics.rs:5:3 + | +LL | fn<'a, B: 'a + std::ops::Add<Output = u32>> f(_x: B) { } + | ^ expected identifier + | +help: place the generic parameter name after the fn name + | +LL - fn<'a, B: 'a + std::ops::Add<Output = u32>> f(_x: B) { } +LL + fn f<'a, B: 'a + std::ops::Add<Output = u32>>(_x: B) { } + | + +error: aborting due to previous error + diff --git a/tests/ui/parser/suggest_misplaced_generics/fn-invalid-generics.rs b/tests/ui/parser/suggest_misplaced_generics/fn-invalid-generics.rs new file mode 100644 index 00000000000..7fcb6a82ce4 --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/fn-invalid-generics.rs @@ -0,0 +1,8 @@ +// Issue: 103366 , Suggest fix for misplaced generic params +// The generics fail to parse here, so don't make any suggestions/help + +#[allow(unused)] +fn<~>()> id(x: T) -> T { x } +//~^ ERROR expected identifier, found `<` + +fn main() {} diff --git a/tests/ui/parser/suggest_misplaced_generics/fn-invalid-generics.stderr b/tests/ui/parser/suggest_misplaced_generics/fn-invalid-generics.stderr new file mode 100644 index 00000000000..47e12016938 --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/fn-invalid-generics.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found `<` + --> $DIR/fn-invalid-generics.rs:5:3 + | +LL | fn<~>()> id(x: T) -> T { x } + | ^ expected identifier + +error: aborting due to previous error + diff --git a/tests/ui/parser/suggest_misplaced_generics/fn-simple.fixed b/tests/ui/parser/suggest_misplaced_generics/fn-simple.fixed new file mode 100644 index 00000000000..cbfd5f2d39c --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/fn-simple.fixed @@ -0,0 +1,9 @@ +// Issue: 103366 , Suggest fix for misplaced generic params +// run-rustfix + +#[allow(unused)] +fn id<T>(x: T) -> T { x } +//~^ ERROR expected identifier, found `<` +//~| HELP place the generic parameter name after the fn name + +fn main() {} diff --git a/tests/ui/parser/suggest_misplaced_generics/fn-simple.rs b/tests/ui/parser/suggest_misplaced_generics/fn-simple.rs new file mode 100644 index 00000000000..b207cf70d85 --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/fn-simple.rs @@ -0,0 +1,9 @@ +// Issue: 103366 , Suggest fix for misplaced generic params +// run-rustfix + +#[allow(unused)] +fn<T> id(x: T) -> T { x } +//~^ ERROR expected identifier, found `<` +//~| HELP place the generic parameter name after the fn name + +fn main() {} diff --git a/tests/ui/parser/suggest_misplaced_generics/fn-simple.stderr b/tests/ui/parser/suggest_misplaced_generics/fn-simple.stderr new file mode 100644 index 00000000000..e749f1a0d00 --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/fn-simple.stderr @@ -0,0 +1,14 @@ +error: expected identifier, found `<` + --> $DIR/fn-simple.rs:5:3 + | +LL | fn<T> id(x: T) -> T { x } + | ^ expected identifier + | +help: place the generic parameter name after the fn name + | +LL - fn<T> id(x: T) -> T { x } +LL + fn id<T>(x: T) -> T { x } + | + +error: aborting due to previous error + diff --git a/tests/ui/parser/suggest_misplaced_generics/struct.fixed b/tests/ui/parser/suggest_misplaced_generics/struct.fixed new file mode 100644 index 00000000000..fec05bdeca1 --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/struct.fixed @@ -0,0 +1,9 @@ +// Issue: 103366 , Suggest fix for misplaced generic params +// run-rustfix + +#[allow(unused)] +struct Foo<T> { x: T } +//~^ ERROR expected identifier, found `<` +//~| HELP place the generic parameter name after the struct name + +fn main() {} diff --git a/tests/ui/parser/suggest_misplaced_generics/struct.rs b/tests/ui/parser/suggest_misplaced_generics/struct.rs new file mode 100644 index 00000000000..6b80150d546 --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/struct.rs @@ -0,0 +1,9 @@ +// Issue: 103366 , Suggest fix for misplaced generic params +// run-rustfix + +#[allow(unused)] +struct<T> Foo { x: T } +//~^ ERROR expected identifier, found `<` +//~| HELP place the generic parameter name after the struct name + +fn main() {} diff --git a/tests/ui/parser/suggest_misplaced_generics/struct.stderr b/tests/ui/parser/suggest_misplaced_generics/struct.stderr new file mode 100644 index 00000000000..2b650907092 --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/struct.stderr @@ -0,0 +1,14 @@ +error: expected identifier, found `<` + --> $DIR/struct.rs:5:7 + | +LL | struct<T> Foo { x: T } + | ^ expected identifier + | +help: place the generic parameter name after the struct name + | +LL - struct<T> Foo { x: T } +LL + struct Foo<T> { x: T } + | + +error: aborting due to previous error + diff --git a/tests/ui/parser/suggest_misplaced_generics/trait.fixed b/tests/ui/parser/suggest_misplaced_generics/trait.fixed new file mode 100644 index 00000000000..a471a078af1 --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/trait.fixed @@ -0,0 +1,11 @@ +// Issue: 103366 , Suggest fix for misplaced generic params +// run-rustfix + +#[allow(unused)] +trait Foo<T> { + //~^ ERROR expected identifier, found `<` + //~| HELP place the generic parameter name after the trait name +} + + +fn main() {} diff --git a/tests/ui/parser/suggest_misplaced_generics/trait.rs b/tests/ui/parser/suggest_misplaced_generics/trait.rs new file mode 100644 index 00000000000..55355f451f9 --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/trait.rs @@ -0,0 +1,11 @@ +// Issue: 103366 , Suggest fix for misplaced generic params +// run-rustfix + +#[allow(unused)] +trait<T> Foo { + //~^ ERROR expected identifier, found `<` + //~| HELP place the generic parameter name after the trait name +} + + +fn main() {} diff --git a/tests/ui/parser/suggest_misplaced_generics/trait.stderr b/tests/ui/parser/suggest_misplaced_generics/trait.stderr new file mode 100644 index 00000000000..ac86cfa4697 --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/trait.stderr @@ -0,0 +1,14 @@ +error: expected identifier, found `<` + --> $DIR/trait.rs:5:6 + | +LL | trait<T> Foo { + | ^ expected identifier + | +help: place the generic parameter name after the trait name + | +LL - trait<T> Foo { +LL + trait Foo<T> { + | + +error: aborting due to previous error + diff --git a/tests/ui/parser/suggest_misplaced_generics/type.fixed b/tests/ui/parser/suggest_misplaced_generics/type.fixed new file mode 100644 index 00000000000..a97b9e66d0b --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/type.fixed @@ -0,0 +1,9 @@ +// Issue: 103366 , Suggest fix for misplaced generic params +// run-rustfix + +#[allow(unused)] +type Foo<T> = T; +//~^ ERROR expected identifier, found `<` +//~| HELP place the generic parameter name after the type name + +fn main() {} diff --git a/tests/ui/parser/suggest_misplaced_generics/type.rs b/tests/ui/parser/suggest_misplaced_generics/type.rs new file mode 100644 index 00000000000..17e200536fa --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/type.rs @@ -0,0 +1,9 @@ +// Issue: 103366 , Suggest fix for misplaced generic params +// run-rustfix + +#[allow(unused)] +type<T> Foo = T; +//~^ ERROR expected identifier, found `<` +//~| HELP place the generic parameter name after the type name + +fn main() {} diff --git a/tests/ui/parser/suggest_misplaced_generics/type.stderr b/tests/ui/parser/suggest_misplaced_generics/type.stderr new file mode 100644 index 00000000000..22744f6cf37 --- /dev/null +++ b/tests/ui/parser/suggest_misplaced_generics/type.stderr @@ -0,0 +1,14 @@ +error: expected identifier, found `<` + --> $DIR/type.rs:5:5 + | +LL | type<T> Foo = T; + | ^ expected identifier + | +help: place the generic parameter name after the type name + | +LL - type<T> Foo = T; +LL + type Foo<T> = T; + | + +error: aborting due to previous error + diff --git a/tests/ui/single-use-lifetime/issue-107998.rs b/tests/ui/single-use-lifetime/issue-107998.rs new file mode 100644 index 00000000000..f32688d2058 --- /dev/null +++ b/tests/ui/single-use-lifetime/issue-107998.rs @@ -0,0 +1,9 @@ +#![deny(single_use_lifetimes)] + +fn with<R>(f: &fn<'a>(x: &'a i32) -> R) -> R { + //~^ ERROR function pointer types may not have generic parameters + //~| ERROR lifetime parameter `'a` only used once + f(&3) +} + +fn main() {} diff --git a/tests/ui/single-use-lifetime/issue-107998.stderr b/tests/ui/single-use-lifetime/issue-107998.stderr new file mode 100644 index 00000000000..e870351de9e --- /dev/null +++ b/tests/ui/single-use-lifetime/issue-107998.stderr @@ -0,0 +1,30 @@ +error: function pointer types may not have generic parameters + --> $DIR/issue-107998.rs:3:18 + | +LL | fn with<R>(f: &fn<'a>(x: &'a i32) -> R) -> R { + | ^^^^ + | +help: consider moving the lifetime parameter to a `for` parameter list + | +LL - fn with<R>(f: &fn<'a>(x: &'a i32) -> R) -> R { +LL + fn with<R>(f: &for<'a> fn(x: &'a i32) -> R) -> R { + | + +error: lifetime parameter `'a` only used once + --> $DIR/issue-107998.rs:3:19 + | +LL | fn with<R>(f: &fn<'a>(x: &'a i32) -> R) -> R { + | ^^ --- + | | | + | | ...is used only here + | | help: elide the single-use lifetime + | this lifetime... + | +note: the lint level is defined here + --> $DIR/issue-107998.rs:1:9 + | +LL | #![deny(single_use_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/traits/issue-103563.rs b/tests/ui/traits/issue-103563.rs new file mode 100644 index 00000000000..cd3eea09b99 --- /dev/null +++ b/tests/ui/traits/issue-103563.rs @@ -0,0 +1,75 @@ +// build-pass + +fn main() { + let mut log_service = LogService { inner: Inner }; + log_service.call(()); +} + +pub trait Service<Request> { + type Response; + + fn call(&mut self, req: Request) -> Self::Response; +} + +pub struct LogService<S> { + inner: S, +} + +impl<T, U, S> Service<T> for LogService<S> +where + S: Service<T, Response = U>, + U: Extension + 'static, + for<'a> U::Item<'a>: std::fmt::Debug, +{ + type Response = S::Response; + + fn call(&mut self, req: T) -> Self::Response { + self.inner.call(req) + } +} + +pub struct Inner; + +impl Service<()> for Inner { + type Response = Resp; + + fn call(&mut self, req: ()) -> Self::Response { + Resp::A(req) + } +} + +pub trait Extension { + type Item<'a>; + + fn touch<F>(self, f: F) -> Self + where + for<'a> F: Fn(Self::Item<'a>); +} + +pub enum Resp { + A(()), +} + +impl Extension for Resp { + type Item<'a> = RespItem<'a>; + fn touch<F>(self, _f: F) -> Self + where + for<'a> F: Fn(Self::Item<'a>), + { + match self { + Self::A(a) => Self::A(a), + } + } +} + +pub enum RespItem<'a> { + A(&'a ()), +} + +impl<'a> std::fmt::Debug for RespItem<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::A(arg0) => f.debug_tuple("A").field(arg0).finish(), + } + } +} diff --git a/triagebot.toml b/triagebot.toml index 62a99b70438..883bc8720e2 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -468,6 +468,9 @@ This was probably unintentional and should be reverted before this PR is merged. If this was intentional then you can ignore this comment. """ +[mentions."src/tools/x"] +message = "`src/tools/x` was changed. Bump version of Cargo.toml in `src/tools/x` so tidy will suggest installing the new version." + [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/contributing.html" |
