diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e1d0d5a1c7af2..1b8e2999afe6a 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -148,11 +148,11 @@ pub struct LoweringContext<'a> { pub trait Resolver { /// Resolve a path generated by the lowerer when expanding `for`, `if let`, etc. - fn resolve_hir_path( + fn resolve_ast_path( &mut self, path: &ast::Path, is_value: bool, - ) -> hir::Path; + ) -> Res; /// Obtain resolution for a `NodeId` with a single resolution. fn get_partial_res(&mut self, id: NodeId) -> Option; @@ -167,7 +167,7 @@ pub trait Resolver { /// This should only return `None` during testing. fn definitions(&mut self) -> &mut Definitions; - /// Given suffix `["b", "c", "d"]`, creates a HIR path for `[::crate_root]::b::c::d` and + /// Given suffix `["b", "c", "d"]`, creates an AST path for `[::crate_root]::b::c::d` and /// resolves it based on `is_value`. fn resolve_str_path( &mut self, @@ -175,7 +175,7 @@ pub trait Resolver { crate_root: Option, components: &[Symbol], is_value: bool, - ) -> hir::Path; + ) -> (ast::Path, Res); } /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree, @@ -5546,16 +5546,26 @@ impl<'a> LoweringContext<'a> { params: Option>, is_value: bool, ) -> hir::Path { - let mut path = self.resolver + let (path, res) = self.resolver .resolve_str_path(span, self.crate_root, components, is_value); - path.segments.last_mut().unwrap().args = params; - for seg in path.segments.iter_mut() { - if seg.hir_id.is_some() { - seg.hir_id = Some(self.next_id()); + let mut segments: Vec<_> = path.segments.iter().map(|segment| { + let res = self.expect_full_res(segment.id); + hir::PathSegment { + ident: segment.ident, + hir_id: Some(self.lower_node_id(segment.id)), + res: Some(self.lower_res(res)), + infer_args: true, + args: None, } + }).collect(); + segments.last_mut().unwrap().args = params; + + hir::Path { + span, + res: res.map_id(|_| panic!("unexpected node_id")), + segments: segments.into(), } - path } fn ty_path(&mut self, mut hir_id: hir::HirId, span: Span, qpath: hir::QPath) -> hir::Ty { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 3b418d0dbb665..81adfac0a291a 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1744,12 +1744,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 /// the resolver is no longer needed as all the relevant information is inline. impl<'a> hir::lowering::Resolver for Resolver<'a> { - fn resolve_hir_path( + fn resolve_ast_path( &mut self, path: &ast::Path, is_value: bool, - ) -> hir::Path { - self.resolve_hir_path_cb(path, is_value, + ) -> Res { + self.resolve_ast_path_cb(path, is_value, |resolver, span, error| resolve_error(resolver, span, error)) } @@ -1759,7 +1759,7 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { crate_root: Option, components: &[Symbol], is_value: bool - ) -> hir::Path { + ) -> (ast::Path, Res) { let root = if crate_root.is_some() { kw::PathRoot } else { @@ -1777,7 +1777,8 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { segments, }; - self.resolve_hir_path(&path, is_value) + let res = self.resolve_ast_path(&path, is_value); + (path, res) } fn get_partial_res(&mut self, id: NodeId) -> Option { @@ -1803,7 +1804,7 @@ impl<'a> Resolver<'a> { /// and also it's a private type. Fortunately rustdoc doesn't need to know the error, /// just that an error occurred. pub fn resolve_str_path_error(&mut self, span: Span, path_str: &str, is_value: bool) - -> Result { + -> Result<(ast::Path, Res), ()> { let mut errored = false; let path = if path_str.starts_with("::") { @@ -1826,29 +1827,29 @@ impl<'a> Resolver<'a> { .collect(), } }; - let path = self.resolve_hir_path_cb(&path, is_value, |_, _, _| errored = true); - if errored || path.res == def::Res::Err { + let res = self.resolve_ast_path_cb(&path, is_value, |_, _, _| errored = true); + if errored || res == def::Res::Err { Err(()) } else { - Ok(path) + Ok((path, res)) } } - /// Like `resolve_hir_path`, but takes a callback in case there was an error. - fn resolve_hir_path_cb( + /// Like `resolve_ast_path`, but takes a callback in case there was an error. + // FIXME(eddyb) use `Result` or something instead of callbacks. + fn resolve_ast_path_cb( &mut self, path: &ast::Path, is_value: bool, error_callback: F, - ) -> hir::Path + ) -> Res where F: for<'c, 'b> FnOnce(&'c mut Resolver<'_>, Span, ResolutionError<'b>) { let namespace = if is_value { ValueNS } else { TypeNS }; let span = path.span; - let segments = &path.segments; let path = Segment::from_path(&path); // FIXME(Manishearth): intra-doc links won't get warned of epoch changes. - let res = match self.resolve_path_without_parent_scope(&path, Some(namespace), true, + match self.resolve_path_without_parent_scope(&path, Some(namespace), true, span, CrateLint::No) { PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res().unwrap(), @@ -1869,19 +1870,6 @@ impl<'a> Resolver<'a> { }); Res::Err } - }; - - let segments: Vec<_> = segments.iter().map(|seg| { - let mut hir_seg = hir::PathSegment::from_ident(seg.ident); - hir_seg.res = Some(self.partial_res_map.get(&seg.id).map_or(def::Res::Err, |p| { - p.base_res().map_id(|_| panic!("unexpected node_id")) - })); - hir_seg - }).collect(); - hir::Path { - span, - res: res.map_id(|_| panic!("unexpected node_id")), - segments: segments.into(), } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index e6f09927796fa..bb85fe898dabd 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -71,15 +71,16 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }) }); - if let Ok(result) = result { + if let Ok((_, res)) = result { + let res = res.map_id(|_| panic!("unexpected node_id")); // In case this is a trait item, skip the // early return and try looking for the trait. - let value = match result.res { + let value = match res { Res::Def(DefKind::Method, _) | Res::Def(DefKind::AssocConst, _) => true, Res::Def(DefKind::AssocTy, _) => false, - Res::Def(DefKind::Variant, _) => return handle_variant(cx, result.res), + Res::Def(DefKind::Variant, _) => return handle_variant(cx, res), // Not a trait item; just return what we found. - _ => return Ok((result.res, None)) + _ => return Ok((res, None)) }; if value != (ns == ValueNS) { @@ -129,10 +130,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // FIXME: `with_scope` requires the `NodeId` of a module. let node_id = cx.tcx.hir().hir_to_node_id(id); - let ty = cx.enter_resolver(|resolver| resolver.with_scope(node_id, |resolver| { + let (_, ty_res) = cx.enter_resolver(|resolver| resolver.with_scope(node_id, |resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path, false) }))?; - match ty.res { + let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); + match ty_res { Res::Def(DefKind::Struct, did) | Res::Def(DefKind::Union, did) | Res::Def(DefKind::Enum, did) @@ -147,7 +149,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ty::AssocKind::Const if ns == ValueNS => "associatedconstant", _ => return Err(()) }; - Ok((ty.res, Some(format!("{}.{}", out, item_name)))) + Ok((ty_res, Some(format!("{}.{}", out, item_name)))) } else { match cx.tcx.type_of(did).sty { ty::Adt(def, _) => { @@ -159,7 +161,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .iter() .find(|item| item.ident.name == item_name) } { - Ok((ty.res, + Ok((ty_res, Some(format!("{}.{}", if def.is_enum() { "variant" @@ -193,7 +195,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { _ => return Err(()) }; - Ok((ty.res, Some(format!("{}.{}", kind, item_name)))) + Ok((ty_res, Some(format!("{}.{}", kind, item_name)))) } else { Err(()) }