diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5a87dede54e..f8bc1f80471 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -71,7 +71,7 @@ use rustc_span::{Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; -use std::{cmp, fmt, iter, mem, ptr}; +use std::{cmp, fmt, mem, ptr}; use tracing::debug; use diagnostics::{extend_span_to_previous_binding, find_span_of_binding_until_next_binding}; @@ -3309,82 +3309,39 @@ impl<'a> Resolver<'a> { }) } - /// Rustdoc uses this to resolve things in a recoverable way. `ResolutionError<'a>` + /// Rustdoc uses this to resolve doc link paths in a recoverable way. `PathResult<'a>` /// isn't something that can be returned because it can't be made to live that long, /// and also it's a private type. Fortunately rustdoc doesn't need to know the error, /// just that an error occurred. - // FIXME(Manishearth): intra-doc links won't get warned of epoch changes. - pub fn resolve_str_path_error( + pub fn resolve_rustdoc_path( &mut self, - span: Span, path_str: &str, ns: Namespace, module_id: DefId, - ) -> Result<(ast::Path, Res), ()> { - let path = if path_str.starts_with("::") { - ast::Path { - span, - segments: iter::once(Ident::with_dummy_span(kw::PathRoot)) - .chain(path_str.split("::").skip(1).map(Ident::from_str)) - .map(|i| self.new_ast_path_segment(i)) - .collect(), - tokens: None, - } - } else { - ast::Path { - span, - segments: path_str - .split("::") - .map(Ident::from_str) - .map(|i| self.new_ast_path_segment(i)) - .collect(), - tokens: None, - } - }; - let module = self.expect_module(module_id); - let parent_scope = &ParentScope::module(module, self); - let res = self.resolve_ast_path(&path, ns, parent_scope).map_err(|_| ())?; - Ok((path, res)) - } + ) -> Option { + let mut segments = + Vec::from_iter(path_str.split("::").map(Ident::from_str).map(Segment::from_ident)); + if path_str.starts_with("::") { + segments[0].ident.name = kw::PathRoot; + } - // Resolve a path passed from rustdoc or HIR lowering. - fn resolve_ast_path( - &mut self, - path: &ast::Path, - ns: Namespace, - parent_scope: &ParentScope<'a>, - ) -> Result)> { + let module = self.expect_module(module_id); match self.resolve_path( - &Segment::from_path(path), + &segments, Some(ns), - parent_scope, - path.span, + &ParentScope::module(module, self), + DUMMY_SP, CrateLint::No, ) { - PathResult::Module(ModuleOrUniformRoot::Module(module)) => Ok(module.res().unwrap()), + PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()), PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { - Ok(path_res.base_res()) + Some(path_res.base_res()) } - PathResult::NonModule(..) => Err(( - path.span, - ResolutionError::FailedToResolve { - label: String::from("type-relative paths are not supported in this context"), - suggestion: None, - }, - )), + PathResult::NonModule(..) | PathResult::Failed { .. } => None, PathResult::Module(..) | PathResult::Indeterminate => unreachable!(), - PathResult::Failed { span, label, suggestion, .. } => { - Err((span, ResolutionError::FailedToResolve { label, suggestion })) - } } } - fn new_ast_path_segment(&mut self, ident: Ident) -> ast::PathSegment { - let mut seg = ast::PathSegment::from_ident(ident); - seg.id = self.next_node_id(); - seg - } - // For rustdoc. pub fn graph_root(&self) -> Module<'a> { self.graph_root diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 3d8a62d50e0..5b14aca064e 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -487,12 +487,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { module_id: DefId, ) -> Result> { self.cx.enter_resolver(|resolver| { - // NOTE: this needs 2 separate lookups because `resolve_str_path_error` doesn't take + // NOTE: this needs 2 separate lookups because `resolve_rustdoc_path` doesn't take // lexical scope into account (it ignores all macros not defined at the mod-level) debug!("resolving {} as a macro in the module {:?}", path_str, module_id); - if let Ok((_, res)) = - resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id) - { + if let Some(res) = resolver.resolve_rustdoc_path(path_str, MacroNS, module_id) { // don't resolve builtins like `#[derive]` if let Ok(res) = res.try_into() { return Ok(res); @@ -540,10 +538,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }) } - /// Convenience wrapper around `resolve_str_path_error`. + /// Convenience wrapper around `resolve_rustdoc_path`. /// /// This also handles resolving `true` and `false` as booleans. - /// NOTE: `resolve_str_path_error` knows only about paths, not about types. + /// NOTE: `resolve_rustdoc_path` knows only about paths, not about types. /// Associated items will never be resolved by this function. fn resolve_path( &self, @@ -556,18 +554,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { return res; } - let result = self.cx.enter_resolver(|resolver| { - resolver - .resolve_str_path_error(DUMMY_SP, path_str, ns, module_id) - .and_then(|(_, res)| res.try_into()) - }); + // Resolver doesn't know about true, false, and types that aren't paths (e.g. `()`). + let result = self + .cx + .enter_resolver(|resolver| resolver.resolve_rustdoc_path(path_str, ns, module_id)) + .and_then(|res| res.try_into().ok()) + .or_else(|| resolve_primitive(path_str, ns)); debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); - match result { - // resolver doesn't know about true, false, and types that aren't paths (e.g. `()`) - // manually as bool - Err(()) => resolve_primitive(path_str, ns), - Ok(res) => Some(res), - } + result } /// Resolves a string as a path within a particular namespace. Returns an diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs index 1d28bbde79c..30636faf98c 100644 --- a/src/librustdoc/passes/collect_intra_doc_links/early.rs +++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs @@ -13,7 +13,7 @@ use rustc_hir::TraitCandidate; use rustc_middle::ty::{DefIdTree, Visibility}; use rustc_resolve::{ParentScope, Resolver}; use rustc_session::config::Externs; -use rustc_span::{Span, SyntaxContext, DUMMY_SP}; +use rustc_span::SyntaxContext; use std::collections::hash_map::Entry; use std::mem; @@ -39,7 +39,7 @@ crate fn early_resolve_intra_doc_links( // Overridden `visit_item` below doesn't apply to the crate root, // so we have to visit its attributes and reexports separately. - loader.load_links_in_attrs(&krate.attrs, krate.spans.inner_span); + loader.load_links_in_attrs(&krate.attrs); loader.process_module_children_or_reexports(CRATE_DEF_ID.to_def_id()); visit::walk_crate(&mut loader, krate); loader.add_foreign_traits_in_scope(); @@ -49,12 +49,7 @@ crate fn early_resolve_intra_doc_links( // DO NOT REMOVE THIS without first testing on the reproducer in // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb for (extern_name, _) in externs.iter().filter(|(_, entry)| entry.add_prelude) { - let _ = loader.resolver.resolve_str_path_error( - DUMMY_SP, - extern_name, - TypeNS, - CRATE_DEF_ID.to_def_id(), - ); + loader.resolver.resolve_rustdoc_path(extern_name, TypeNS, CRATE_DEF_ID.to_def_id()); } ResolverCaches { @@ -151,7 +146,7 @@ impl IntraLinkCrateLoader<'_, '_> { } } - fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) { + fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute]) { // FIXME: this needs to consider reexport inlining. let attrs = clean::Attributes::from_ast(attrs, None); for (parent_module, doc) in attrs.collapsed_doc_value_by_module_level() { @@ -165,7 +160,7 @@ impl IntraLinkCrateLoader<'_, '_> { } else { continue; }; - let _ = self.resolver.resolve_str_path_error(span, &path_str, TypeNS, module_id); + self.resolver.resolve_rustdoc_path(&path_str, TypeNS, module_id); } } } @@ -201,7 +196,7 @@ impl Visitor<'_> for IntraLinkCrateLoader<'_, '_> { // loaded, even if the module itself has no doc comments. self.add_traits_in_parent_scope(self.current_mod.to_def_id()); - self.load_links_in_attrs(&item.attrs, item.span); + self.load_links_in_attrs(&item.attrs); self.process_module_children_or_reexports(self.current_mod.to_def_id()); visit::walk_item(self, item); @@ -216,28 +211,28 @@ impl Visitor<'_> for IntraLinkCrateLoader<'_, '_> { } _ => {} } - self.load_links_in_attrs(&item.attrs, item.span); + self.load_links_in_attrs(&item.attrs); visit::walk_item(self, item); } } fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: AssocCtxt) { - self.load_links_in_attrs(&item.attrs, item.span); + self.load_links_in_attrs(&item.attrs); visit::walk_assoc_item(self, item, ctxt) } fn visit_foreign_item(&mut self, item: &ast::ForeignItem) { - self.load_links_in_attrs(&item.attrs, item.span); + self.load_links_in_attrs(&item.attrs); visit::walk_foreign_item(self, item) } fn visit_variant(&mut self, v: &ast::Variant) { - self.load_links_in_attrs(&v.attrs, v.span); + self.load_links_in_attrs(&v.attrs); visit::walk_variant(self, v) } fn visit_field_def(&mut self, field: &ast::FieldDef) { - self.load_links_in_attrs(&field.attrs, field.span); + self.load_links_in_attrs(&field.attrs); visit::walk_field_def(self, field) }