Fix calls to resolver from rustdoc and HIR lowering

Cleanup some surrounding code.
Support resolution of intra doc links in unnamed block scopes.
(Paths from rustdoc now use early resolution and no longer need results of late resolution like all the built ribs.)

Fix one test hitting file path limits on Windows.
This commit is contained in:
Vadim Petrochenkov 2019-08-09 02:16:45 +03:00
parent f360d795f1
commit 8cc8133973
5 changed files with 48 additions and 61 deletions

View file

@ -37,7 +37,7 @@ use crate::hir::{self, ParamName};
use crate::hir::HirVec; use crate::hir::HirVec;
use crate::hir::map::{DefKey, DefPathData, Definitions}; use crate::hir::map::{DefKey, DefPathData, Definitions};
use crate::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use crate::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
use crate::hir::def::{Res, DefKind, PartialRes, PerNS}; use crate::hir::def::{Namespace, Res, DefKind, PartialRes, PerNS};
use crate::hir::{GenericArg, ConstArg}; use crate::hir::{GenericArg, ConstArg};
use crate::hir::ptr::P; use crate::hir::ptr::P;
use crate::lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, use crate::lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
@ -148,13 +148,6 @@ pub struct LoweringContext<'a> {
} }
pub trait Resolver { pub trait Resolver {
/// Resolve a path generated by the lowerer when expanding `for`, `if let`, etc.
fn resolve_ast_path(
&mut self,
path: &ast::Path,
is_value: bool,
) -> Res<NodeId>;
/// Obtain resolution for a `NodeId` with a single resolution. /// Obtain resolution for a `NodeId` with a single resolution.
fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes>; fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes>;
@ -175,7 +168,7 @@ pub trait Resolver {
span: Span, span: Span,
crate_root: Option<Symbol>, crate_root: Option<Symbol>,
components: &[Symbol], components: &[Symbol],
is_value: bool, ns: Namespace,
) -> (ast::Path, Res<NodeId>); ) -> (ast::Path, Res<NodeId>);
fn has_derives(&self, node_id: NodeId, derives: SpecialDerives) -> bool; fn has_derives(&self, node_id: NodeId, derives: SpecialDerives) -> bool;
@ -5717,8 +5710,8 @@ impl<'a> LoweringContext<'a> {
params: Option<P<hir::GenericArgs>>, params: Option<P<hir::GenericArgs>>,
is_value: bool, is_value: bool,
) -> hir::Path { ) -> hir::Path {
let (path, res) = self.resolver let ns = if is_value { Namespace::ValueNS } else { Namespace::TypeNS };
.resolve_str_path(span, self.crate_root, components, is_value); let (path, res) = self.resolver.resolve_str_path(span, self.crate_root, components, ns);
let mut segments: Vec<_> = path.segments.iter().map(|segment| { let mut segments: Vec<_> = path.segments.iter().map(|segment| {
let res = self.expect_full_res(segment.id); let res = self.expect_full_res(segment.id);

View file

@ -541,7 +541,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
crate_lint: CrateLint, crate_lint: CrateLint,
) -> PathResult<'a> { ) -> PathResult<'a> {
self.r.resolve_path_with_ribs( self.r.resolve_path_with_ribs(
path, opt_ns, &self.parent_scope, record_used, path_span, crate_lint, &self.ribs path, opt_ns, &self.parent_scope, record_used, path_span, crate_lint, Some(&self.ribs)
) )
} }

View file

@ -987,26 +987,12 @@ impl<'a, 'b> ty::DefIdTree for &'a Resolver<'b> {
/// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that /// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that
/// the resolver is no longer needed as all the relevant information is inline. /// the resolver is no longer needed as all the relevant information is inline.
impl<'a> hir::lowering::Resolver for Resolver<'a> { impl<'a> hir::lowering::Resolver for Resolver<'a> {
fn resolve_ast_path(
&mut self,
path: &ast::Path,
is_value: bool,
) -> Res {
match self.resolve_ast_path_inner(path, is_value) {
Ok(r) => r,
Err((span, error)) => {
self.report_error(span, error);
Res::Err
}
}
}
fn resolve_str_path( fn resolve_str_path(
&mut self, &mut self,
span: Span, span: Span,
crate_root: Option<Symbol>, crate_root: Option<Symbol>,
components: &[Symbol], components: &[Symbol],
is_value: bool ns: Namespace,
) -> (ast::Path, Res) { ) -> (ast::Path, Res) {
let root = if crate_root.is_some() { let root = if crate_root.is_some() {
kw::PathRoot kw::PathRoot
@ -1025,7 +1011,14 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
segments, segments,
}; };
let res = self.resolve_ast_path(&path, is_value); let parent_scope = &self.dummy_parent_scope();
let res = match self.resolve_ast_path(&path, ns, parent_scope) {
Ok(res) => res,
Err((span, error)) => {
self.report_error(span, error);
Res::Err
}
};
(path, res) (path, res)
} }
@ -1738,7 +1731,7 @@ impl<'a> Resolver<'a> {
crate_lint: CrateLint, crate_lint: CrateLint,
) -> PathResult<'a> { ) -> PathResult<'a> {
self.resolve_path_with_ribs( self.resolve_path_with_ribs(
path, opt_ns, parent_scope, record_used, path_span, crate_lint, &Default::default() path, opt_ns, parent_scope, record_used, path_span, crate_lint, None
) )
} }
@ -1750,7 +1743,7 @@ impl<'a> Resolver<'a> {
record_used: bool, record_used: bool,
path_span: Span, path_span: Span,
crate_lint: CrateLint, crate_lint: CrateLint,
ribs: &PerNS<Vec<Rib<'a>>>, ribs: Option<&PerNS<Vec<Rib<'a>>>>,
) -> PathResult<'a> { ) -> PathResult<'a> {
let mut module = None; let mut module = None;
let mut allow_super = true; let mut allow_super = true;
@ -1864,16 +1857,17 @@ impl<'a> Resolver<'a> {
self.resolve_ident_in_module( self.resolve_ident_in_module(
module, ident, ns, parent_scope, record_used, path_span module, ident, ns, parent_scope, record_used, path_span
) )
} else if opt_ns.is_none() || opt_ns == Some(MacroNS) { } else if ribs.is_none() || opt_ns.is_none() || opt_ns == Some(MacroNS) {
assert!(ns == TypeNS); // FIXME: Decouple the import property from `ScopeSet`.
let scopes = if opt_ns.is_none() { ScopeSet::Import(ns) } else { ScopeSet::Module }; let is_import = opt_ns.is_none() || ns != TypeNS;
let scopes = if is_import { ScopeSet::Import(ns) } else { ScopeSet::Module };
self.early_resolve_ident_in_lexical_scope(ident, scopes, parent_scope, record_used, self.early_resolve_ident_in_lexical_scope(ident, scopes, parent_scope, record_used,
record_used, path_span) record_used, path_span)
} else { } else {
let record_used_id = let record_used_id =
if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None }; if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None };
match self.resolve_ident_in_lexical_scope( match self.resolve_ident_in_lexical_scope(
ident, ns, parent_scope, record_used_id, path_span, &ribs[ns] ident, ns, parent_scope, record_used_id, path_span, &ribs.unwrap()[ns]
) { ) {
// we found a locally-imported or available item/module // we found a locally-imported or available item/module
Some(LexicalScopeBinding::Item(binding)) => Ok(binding), Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
@ -2639,8 +2633,10 @@ impl<'a> Resolver<'a> {
/// isn't something that can be returned because it can't be made to live that long, /// 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, /// and also it's a private type. Fortunately rustdoc doesn't need to know the error,
/// just that an error occurred. /// just that an error occurred.
pub fn resolve_str_path_error(&mut self, span: Span, path_str: &str, is_value: bool) // FIXME(Manishearth): intra-doc links won't get warned of epoch changes.
-> Result<(ast::Path, Res), ()> { pub fn resolve_str_path_error(
&mut self, span: Span, path_str: &str, ns: Namespace, module_id: NodeId
) -> Result<(ast::Path, Res), ()> {
let path = if path_str.starts_with("::") { let path = if path_str.starts_with("::") {
ast::Path { ast::Path {
span, span,
@ -2661,28 +2657,31 @@ impl<'a> Resolver<'a> {
.collect(), .collect(),
} }
}; };
let res = self.resolve_ast_path_inner(&path, is_value).map_err(|_| ())?; let module = self.block_map.get(&module_id).copied().unwrap_or_else(|| {
let def_id = self.definitions.local_def_id(module_id);
self.module_map.get(&def_id).copied().unwrap_or(self.graph_root)
});
let parent_scope = &ParentScope { module, ..self.dummy_parent_scope() };
let res = self.resolve_ast_path(&path, ns, parent_scope).map_err(|_| ())?;
Ok((path, res)) Ok((path, res))
} }
/// Like `resolve_ast_path`, but takes a callback in case there was an error. // Resolve a path passed from rustdoc or HIR lowering.
fn resolve_ast_path_inner( fn resolve_ast_path(
&mut self, &mut self,
path: &ast::Path, path: &ast::Path,
is_value: bool, ns: Namespace,
parent_scope: &ParentScope<'a>,
) -> Result<Res, (Span, ResolutionError<'a>)> { ) -> Result<Res, (Span, ResolutionError<'a>)> {
let namespace = if is_value { ValueNS } else { TypeNS }; match self.resolve_path(
let span = path.span; &Segment::from_path(path), Some(ns), parent_scope, true, path.span, CrateLint::No
let path = Segment::from_path(&path); ) {
// FIXME(Manishearth): intra-doc links won't get warned of epoch changes.
let parent_scope = &self.dummy_parent_scope();
match self.resolve_path(&path, Some(namespace), parent_scope, true, span, CrateLint::No) {
PathResult::Module(ModuleOrUniformRoot::Module(module)) => PathResult::Module(ModuleOrUniformRoot::Module(module)) =>
Ok(module.res().unwrap()), Ok(module.res().unwrap()),
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 =>
Ok(path_res.base_res()), Ok(path_res.base_res()),
PathResult::NonModule(..) => { PathResult::NonModule(..) => {
Err((span, ResolutionError::FailedToResolve { Err((path.span, ResolutionError::FailedToResolve {
label: String::from("type-relative paths are not supported in this context"), label: String::from("type-relative paths are not supported in this context"),
suggestion: None, suggestion: None,
})) }))

View file

@ -61,15 +61,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
{ {
let cx = self.cx; let cx = self.cx;
// In case we're in a module, try to resolve the relative // In case we're in a module, try to resolve the relative path.
// path. if let Some(module_id) = parent_id.or(self.mod_ids.last().cloned()) {
if let Some(id) = parent_id.or(self.mod_ids.last().cloned()) { let module_id = cx.tcx.hir().hir_to_node_id(module_id);
// FIXME: `with_scope` requires the `NodeId` of a module.
let node_id = cx.tcx.hir().hir_to_node_id(id);
let result = cx.enter_resolver(|resolver| { let result = cx.enter_resolver(|resolver| {
resolver.with_scope(node_id, |resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns == ValueNS)
})
}); });
let result = match result { let result = match result {
Ok((_, Res::Err)) => Err(()), Ok((_, Res::Err)) => Err(()),
@ -85,6 +81,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
Res::Def(DefKind::AssocTy, _) => false, Res::Def(DefKind::AssocTy, _) => false,
Res::Def(DefKind::Variant, _) => return handle_variant(cx, res), Res::Def(DefKind::Variant, _) => return handle_variant(cx, res),
// Not a trait item; just return what we found. // Not a trait item; just return what we found.
Res::PrimTy(..) => return Ok((res, Some(path_str.to_owned()))),
_ => return Ok((res, None)) _ => return Ok((res, None))
}; };
@ -133,11 +130,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
.ok_or(()); .ok_or(());
} }
// FIXME: `with_scope` requires the `NodeId` of a module. let (_, ty_res) = cx.enter_resolver(|resolver| {
let node_id = cx.tcx.hir().hir_to_node_id(id); resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id)
let (_, ty_res) = cx.enter_resolver(|resolver| resolver.with_scope(node_id, |resolver| { })?;
resolver.resolve_str_path_error(DUMMY_SP, &path, false)
}))?;
if let Res::Err = ty_res { if let Res::Err = ty_res {
return Err(()); return Err(());
} }

View file

@ -1,5 +1,5 @@
// edition:2018 // edition:2018
// build-pass (FIXME(62277): could be check-pass?) // check-pass
// revisions: migrate mir // revisions: migrate mir
//[mir]compile-flags: -Z borrowck=mir //[mir]compile-flags: -Z borrowck=mir