about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.mailmap1
-rw-r--r--Cargo.lock4
-rw-r--r--src/librustc_codegen_ssa/back/link.rs14
-rw-r--r--src/librustc_codegen_ssa/back/linker.rs15
-rw-r--r--src/librustc_driver/lib.rs16
-rw-r--r--src/librustc_hir_pretty/lib.rs24
-rw-r--r--src/librustc_interface/interface.rs24
-rw-r--r--src/librustc_middle/ty/mod.rs2
-rw-r--r--src/librustc_resolve/diagnostics.rs11
-rw-r--r--src/librustc_resolve/late.rs146
-rw-r--r--src/librustc_resolve/lib.rs14
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs916
-rw-r--r--src/librustc_save_analysis/lib.rs473
-rw-r--r--src/librustc_save_analysis/sig.rs471
-rw-r--r--src/librustc_span/lib.rs45
-rw-r--r--src/librustc_target/spec/mod.rs6
-rw-r--r--src/librustc_target/spec/tests/tests_impl.rs1
-rw-r--r--src/librustc_target/spec/vxworks_base.rs3
-rw-r--r--src/librustc_trait_selection/opaque_types.rs3
-rw-r--r--src/test/ui/derived-errors/issue-31997-1.stderr9
-rw-r--r--src/test/ui/error-codes/E0433.rs2
-rw-r--r--src/test/ui/error-codes/E0433.stderr6
-rw-r--r--src/test/ui/hygiene/no_implicit_prelude.stderr8
-rw-r--r--src/test/ui/issues/issue-72554.rs20
-rw-r--r--src/test/ui/issues/issue-72554.stderr13
-rw-r--r--src/test/ui/resolve/use_suggestion.rs7
-rw-r--r--src/test/ui/resolve/use_suggestion.stderr42
m---------src/tools/rls0
28 files changed, 1208 insertions, 1088 deletions
diff --git a/.mailmap b/.mailmap
index da17344c208..7f640d40bb7 100644
--- a/.mailmap
+++ b/.mailmap
@@ -44,6 +44,7 @@ Brian Anderson <banderson@mozilla.com> <andersrb@gmail.com>
 Brian Anderson <banderson@mozilla.com> <banderson@mozilla.org>
 Brian Dawn <brian.t.dawn@gmail.com>
 Brian Leibig <brian@brianleibig.com> Brian Leibig <brian.leibig@gmail.com>
+Camelid <camelidcamel@gmail.com> <37223377+camelid@users.noreply.github.com>
 Carl-Anton Ingmarsson <mail@carlanton.se> <ca.ingmarsson@gmail.com>
 Carol (Nichols || Goulding) <carol.nichols@gmail.com> <193874+carols10cents@users.noreply.github.com>
 Carol (Nichols || Goulding) <carol.nichols@gmail.com> <carol.nichols@gmail.com>
diff --git a/Cargo.lock b/Cargo.lock
index 6cfedd4a56d..e33d09bc211 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1853,9 +1853,9 @@ checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
 
 [[package]]
 name = "libc"
-version = "0.2.69"
+version = "0.2.71"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
+checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
 dependencies = [
  "rustc-std-workspace-core",
 ]
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index dcce1d45298..cff84b11aa0 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -1253,20 +1253,10 @@ fn add_post_link_objects(
 
 /// Add arbitrary "pre-link" args defined by the target spec or from command line.
 /// FIXME: Determine where exactly these args need to be inserted.
-fn add_pre_link_args(
-    cmd: &mut dyn Linker,
-    sess: &Session,
-    flavor: LinkerFlavor,
-    crate_type: CrateType,
-) {
+fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
     if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
         cmd.args(args);
     }
-    if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) {
-        if sess.crt_static(Some(crate_type)) {
-            cmd.args(args);
-        }
-    }
     cmd.args(&sess.opts.debugging_opts.pre_link_args);
 }
 
@@ -1502,7 +1492,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     let crt_objects_fallback = crt_objects_fallback(sess, crate_type);
 
     // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
-    add_pre_link_args(cmd, sess, flavor, crate_type);
+    add_pre_link_args(cmd, sess, flavor);
 
     // NO-OPT-OUT
     add_link_script(cmd, sess, tmpdir, crate_type);
diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs
index 77cb31bf3d2..d9fed998c92 100644
--- a/src/librustc_codegen_ssa/back/linker.rs
+++ b/src/librustc_codegen_ssa/back/linker.rs
@@ -315,6 +315,21 @@ impl<'a> Linker for GccLinker<'a> {
                 self.build_dylib(out_filename);
             }
         }
+        // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc,
+        // it switches linking for libc and similar system libraries to static without using
+        // any `#[link]` attributes in the `libc` crate, see #72782 for details.
+        // FIXME: Switch to using `#[link]` attributes in the `libc` crate
+        // similarly to other targets.
+        if self.sess.target.target.target_os == "vxworks"
+            && matches!(
+                output_kind,
+                LinkOutputKind::StaticNoPicExe
+                    | LinkOutputKind::StaticPicExe
+                    | LinkOutputKind::StaticDylib
+            )
+        {
+            self.cmd.arg("--static-crt");
+        }
     }
 
     fn link_dylib(&mut self, lib: Symbol) {
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 68ce93d3db9..ccea041699e 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -346,12 +346,15 @@ pub fn run_compiler(
 
             queries.global_ctxt()?;
 
+            // Drop AST after creating GlobalCtxt to free memory
+            let _timer = sess.prof.generic_activity("drop_ast");
+            mem::drop(queries.expansion()?.take());
+
             if sess.opts.debugging_opts.no_analysis || sess.opts.debugging_opts.ast_json {
                 return early_exit();
             }
 
             if sess.opts.debugging_opts.save_analysis {
-                let expanded_crate = &queries.expansion()?.peek().0;
                 let crate_name = queries.crate_name()?.peek().clone();
                 queries.global_ctxt()?.peek_mut().enter(|tcx| {
                     let result = tcx.analysis(LOCAL_CRATE);
@@ -359,7 +362,6 @@ pub fn run_compiler(
                     sess.time("save_analysis", || {
                         save::process_crate(
                             tcx,
-                            &expanded_crate,
                             &crate_name,
                             &compiler.input(),
                             None,
@@ -371,13 +373,7 @@ pub fn run_compiler(
                     });
 
                     result
-                    // AST will be dropped *after* the `after_analysis` callback
-                    // (needed by the RLS)
                 })?;
-            } else {
-                // Drop AST after creating GlobalCtxt to free memory
-                let _timer = sess.prof.generic_activity("drop_ast");
-                mem::drop(queries.expansion()?.take());
             }
 
             queries.global_ctxt()?.peek_mut().enter(|tcx| tcx.analysis(LOCAL_CRATE))?;
@@ -386,10 +382,6 @@ pub fn run_compiler(
                 return early_exit();
             }
 
-            if sess.opts.debugging_opts.save_analysis {
-                mem::drop(queries.expansion()?.take());
-            }
-
             queries.ongoing_codegen()?;
 
             if sess.opts.debugging_opts.print_type_sizes {
diff --git a/src/librustc_hir_pretty/lib.rs b/src/librustc_hir_pretty/lib.rs
index 8eb19cbb65a..e642915b86a 100644
--- a/src/librustc_hir_pretty/lib.rs
+++ b/src/librustc_hir_pretty/lib.rs
@@ -203,6 +203,30 @@ pub fn visibility_qualified<S: Into<Cow<'static, str>>>(vis: &hir::Visibility<'_
     })
 }
 
+pub fn generic_params_to_string(generic_params: &[GenericParam<'_>]) -> String {
+    to_string(NO_ANN, |s| s.print_generic_params(generic_params))
+}
+
+pub fn bounds_to_string<'b>(bounds: impl IntoIterator<Item = &'b hir::GenericBound<'b>>) -> String {
+    to_string(NO_ANN, |s| s.print_bounds("", bounds))
+}
+
+pub fn param_to_string(arg: &hir::Param<'_>) -> String {
+    to_string(NO_ANN, |s| s.print_param(arg))
+}
+
+pub fn ty_to_string(ty: &hir::Ty<'_>) -> String {
+    to_string(NO_ANN, |s| s.print_type(ty))
+}
+
+pub fn path_segment_to_string(segment: &hir::PathSegment<'_>) -> String {
+    to_string(NO_ANN, |s| s.print_path_segment(segment))
+}
+
+pub fn path_to_string(segment: &hir::Path<'_>) -> String {
+    to_string(NO_ANN, |s| s.print_path(segment, false))
+}
+
 impl<'a> State<'a> {
     pub fn cbox(&mut self, u: usize) {
         self.s.cbox(u);
diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs
index f127a239eea..5aad64f84ce 100644
--- a/src/librustc_interface/interface.rs
+++ b/src/librustc_interface/interface.rs
@@ -186,17 +186,19 @@ pub fn run_compiler_in_existing_thread_pool<R>(
         override_queries: config.override_queries,
     };
 
-    let r = {
-        let _sess_abort_error = OnDrop(|| {
-            compiler.sess.finish_diagnostics(registry);
-        });
-
-        f(&compiler)
-    };
-
-    let prof = compiler.sess.prof.clone();
-    prof.generic_activity("drop_compiler").run(move || drop(compiler));
-    r
+    rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
+        let r = {
+            let _sess_abort_error = OnDrop(|| {
+                compiler.sess.finish_diagnostics(registry);
+            });
+
+            f(&compiler)
+        };
+
+        let prof = compiler.sess.prof.clone();
+        prof.generic_activity("drop_compiler").run(move || drop(compiler));
+        r
+    })
 }
 
 pub fn run_compiler<R: Send>(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs
index a34cff06bc1..00c00a63b6b 100644
--- a/src/librustc_middle/ty/mod.rs
+++ b/src/librustc_middle/ty/mod.rs
@@ -1846,7 +1846,7 @@ pub struct FieldDef {
 
 /// The definition of a user-defined type, e.g., a `struct`, `enum`, or `union`.
 ///
-/// These are all interned (by `intern_adt_def`) into the `adt_defs` table.
+/// These are all interned (by `alloc_adt_def`) into the global arena.
 ///
 /// The initialism *ADT* stands for an [*algebraic data type (ADT)*][adt].
 /// This is slightly wrong because `union`s are not ADTs.
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index ea237f1a04f..cbb2878011c 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -1475,7 +1475,7 @@ crate fn show_candidates(
     // This is `None` if all placement locations are inside expansions
     use_placement_span: Option<Span>,
     candidates: &[ImportSuggestion],
-    better: bool,
+    instead: bool,
     found_use: bool,
 ) {
     if candidates.is_empty() {
@@ -1486,6 +1486,7 @@ crate fn show_candidates(
     // by iterating through a hash map, so make sure they are ordered:
     let mut path_strings: Vec<_> =
         candidates.iter().map(|c| path_names_to_string(&c.path)).collect();
+
     path_strings.sort();
     path_strings.dedup();
 
@@ -1494,8 +1495,9 @@ crate fn show_candidates(
     } else {
         ("one of these", "items")
     };
-    let instead = if better { " instead" } else { "" };
-    let msg = format!("consider importing {} {}{}", determiner, kind, instead);
+
+    let instead = if instead { " instead" } else { "" };
+    let mut msg = format!("consider importing {} {}{}", determiner, kind, instead);
 
     if let Some(span) = use_placement_span {
         for candidate in &mut path_strings {
@@ -1507,12 +1509,13 @@ crate fn show_candidates(
 
         err.span_suggestions(span, &msg, path_strings.into_iter(), Applicability::Unspecified);
     } else {
-        let mut msg = msg;
         msg.push(':');
+
         for candidate in path_strings {
             msg.push('\n');
             msg.push_str(&candidate);
         }
+
         err.note(&msg);
     }
 }
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index 3b49b3b6ff7..2085c8109fd 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -29,8 +29,9 @@ use rustc_span::Span;
 use smallvec::{smallvec, SmallVec};
 
 use log::debug;
+use rustc_span::source_map::{respan, Spanned};
 use std::collections::BTreeSet;
-use std::mem::replace;
+use std::mem::{replace, take};
 
 mod diagnostics;
 crate mod lifetimes;
@@ -234,6 +235,13 @@ impl<'a> PathSource<'a> {
         }
     }
 
+    fn is_call(self) -> bool {
+        match self {
+            PathSource::Expr(Some(&Expr { kind: ExprKind::Call(..), .. })) => true,
+            _ => false,
+        }
+    }
+
     crate fn is_expected(self, res: Res) -> bool {
         match self {
             PathSource::Type => match res {
@@ -1620,14 +1628,83 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
 
         let report_errors = |this: &mut Self, res: Option<Res>| {
             let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
+
             let def_id = this.parent_scope.module.normal_ancestor_id;
-            let better = res.is_some();
+            let instead = res.is_some();
             let suggestion =
                 if res.is_none() { this.report_missing_type_error(path) } else { None };
-            this.r.use_injections.push(UseError { err, candidates, def_id, better, suggestion });
+
+            this.r.use_injections.push(UseError { err, candidates, def_id, instead, suggestion });
+
             PartialRes::new(Res::Err)
         };
 
+        // For paths originating from calls (like in `HashMap::new()`), tries
+        // to enrich the plain `failed to resolve: ...` message with hints
+        // about possible missing imports.
+        //
+        // Similar thing, for types, happens in `report_errors` above.
+        let report_errors_for_call = |this: &mut Self, parent_err: Spanned<ResolutionError<'a>>| {
+            if !source.is_call() {
+                return Some(parent_err);
+            }
+
+            // Before we start looking for candidates, we have to get our hands
+            // on the type user is trying to perform invocation on; basically:
+            // we're transforming `HashMap::new` into just `HashMap`
+            let path = if let Some((_, path)) = path.split_last() {
+                path
+            } else {
+                return Some(parent_err);
+            };
+
+            let (mut err, candidates) =
+                this.smart_resolve_report_errors(path, span, PathSource::Type, None);
+
+            if candidates.is_empty() {
+                err.cancel();
+                return Some(parent_err);
+            }
+
+            // There are two different error messages user might receive at
+            // this point:
+            // - E0412 cannot find type `{}` in this scope
+            // - E0433 failed to resolve: use of undeclared type or module `{}`
+            //
+            // The first one is emitted for paths in type-position, and the
+            // latter one - for paths in expression-position.
+            //
+            // Thus (since we're in expression-position at this point), not to
+            // confuse the user, we want to keep the *message* from E0432 (so
+            // `parent_err`), but we want *hints* from E0412 (so `err`).
+            //
+            // And that's what happens below - we're just mixing both messages
+            // into a single one.
+            let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node);
+
+            parent_err.cancel();
+
+            err.message = take(&mut parent_err.message);
+            err.code = take(&mut parent_err.code);
+            err.children = take(&mut parent_err.children);
+
+            drop(parent_err);
+
+            let def_id = this.parent_scope.module.normal_ancestor_id;
+
+            this.r.use_injections.push(UseError {
+                err,
+                candidates,
+                def_id,
+                instead: false,
+                suggestion: None,
+            });
+
+            // We don't return `Some(parent_err)` here, because the error will
+            // be already printed as part of the `use` injections
+            None
+        };
+
         let partial_res = match self.resolve_qpath_anywhere(
             id,
             qself,
@@ -1637,14 +1714,15 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             source.defer_to_typeck(),
             crate_lint,
         ) {
-            Some(partial_res) if partial_res.unresolved_segments() == 0 => {
+            Ok(Some(partial_res)) if partial_res.unresolved_segments() == 0 => {
                 if is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err {
                     partial_res
                 } else {
                     report_errors(self, Some(partial_res.base_res()))
                 }
             }
-            Some(partial_res) if source.defer_to_typeck() => {
+
+            Ok(Some(partial_res)) if source.defer_to_typeck() => {
                 // Not fully resolved associated item `T::A::B` or `<T as Tr>::A::B`
                 // or `<T>::A::B`. If `B` should be resolved in value namespace then
                 // it needs to be added to the trait map.
@@ -1655,25 +1733,34 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 }
 
                 let mut std_path = vec![Segment::from_ident(Ident::with_dummy_span(sym::std))];
+
                 std_path.extend(path);
+
                 if self.r.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) {
-                    let cl = CrateLint::No;
-                    let ns = Some(ns);
                     if let PathResult::Module(_) | PathResult::NonModule(_) =
-                        self.resolve_path(&std_path, ns, false, span, cl)
+                        self.resolve_path(&std_path, Some(ns), false, span, CrateLint::No)
                     {
-                        // check if we wrote `str::from_utf8` instead of `std::str::from_utf8`
+                        // Check if we wrote `str::from_utf8` instead of `std::str::from_utf8`
                         let item_span =
                             path.iter().last().map(|segment| segment.ident.span).unwrap_or(span);
-                        debug!("accessed item from `std` submodule as a bare type {:?}", std_path);
+
                         let mut hm = self.r.session.confused_type_with_std_module.borrow_mut();
                         hm.insert(item_span, span);
-                        // In some places (E0223) we only have access to the full path
                         hm.insert(span, span);
                     }
                 }
+
                 partial_res
             }
+
+            Err(err) => {
+                if let Some(err) = report_errors_for_call(self, err) {
+                    self.r.report_error(err.span, err.node);
+                }
+
+                PartialRes::new(Res::Err)
+            }
+
             _ => report_errors(self, None),
         };
 
@@ -1682,6 +1769,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             // Avoid recording definition of `A::B` in `<T as A>::B::C`.
             self.r.record_partial_res(id, partial_res);
         }
+
         partial_res
     }
 
@@ -1711,17 +1799,16 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         span: Span,
         defer_to_typeck: bool,
         crate_lint: CrateLint,
-    ) -> Option<PartialRes> {
+    ) -> Result<Option<PartialRes>, Spanned<ResolutionError<'a>>> {
         let mut fin_res = None;
+
         for (i, ns) in [primary_ns, TypeNS, ValueNS].iter().cloned().enumerate() {
             if i == 0 || ns != primary_ns {
-                match self.resolve_qpath(id, qself, path, ns, span, crate_lint) {
-                    // If defer_to_typeck, then resolution > no resolution,
-                    // otherwise full resolution > partial resolution > no resolution.
+                match self.resolve_qpath(id, qself, path, ns, span, crate_lint)? {
                     Some(partial_res)
                         if partial_res.unresolved_segments() == 0 || defer_to_typeck =>
                     {
-                        return Some(partial_res);
+                        return Ok(Some(partial_res));
                     }
                     partial_res => {
                         if fin_res.is_none() {
@@ -1732,19 +1819,19 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             }
         }
 
-        // `MacroNS`
         assert!(primary_ns != MacroNS);
+
         if qself.is_none() {
             let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident);
             let path = Path { segments: path.iter().map(path_seg).collect(), span };
             if let Ok((_, res)) =
                 self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false)
             {
-                return Some(PartialRes::new(res));
+                return Ok(Some(PartialRes::new(res)));
             }
         }
 
-        fin_res
+        Ok(fin_res)
     }
 
     /// Handles paths that may refer to associated items.
@@ -1756,7 +1843,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         ns: Namespace,
         span: Span,
         crate_lint: CrateLint,
-    ) -> Option<PartialRes> {
+    ) -> Result<Option<PartialRes>, Spanned<ResolutionError<'a>>> {
         debug!(
             "resolve_qpath(id={:?}, qself={:?}, path={:?}, ns={:?}, span={:?})",
             id, qself, path, ns, span,
@@ -1767,10 +1854,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 // This is a case like `<T>::B`, where there is no
                 // trait to resolve.  In that case, we leave the `B`
                 // segment to be resolved by type-check.
-                return Some(PartialRes::with_unresolved_segments(
+                return Ok(Some(PartialRes::with_unresolved_segments(
                     Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)),
                     path.len(),
-                ));
+                )));
             }
 
             // Make sure `A::B` in `<T as A::B>::C` is a trait item.
@@ -1800,10 +1887,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             // The remaining segments (the `C` in our example) will
             // have to be resolved by type-check, since that requires doing
             // trait resolution.
-            return Some(PartialRes::with_unresolved_segments(
+            return Ok(Some(PartialRes::with_unresolved_segments(
                 partial_res.base_res(),
                 partial_res.unresolved_segments() + path.len() - qself.position - 1,
-            ));
+            )));
         }
 
         let result = match self.resolve_path(&path, Some(ns), true, span, crate_lint) {
@@ -1838,11 +1925,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 PartialRes::new(module.res().unwrap())
             }
             PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
-                self.r.report_error(span, ResolutionError::FailedToResolve { label, suggestion });
-                PartialRes::new(Res::Err)
+                return Err(respan(span, ResolutionError::FailedToResolve { label, suggestion }));
             }
-            PathResult::Module(..) | PathResult::Failed { .. } => return None,
-            PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"),
+            PathResult::Module(..) | PathResult::Failed { .. } => return Ok(None),
+            PathResult::Indeterminate => bug!("indeterminate path result in resolve_qpath"),
         };
 
         if path.len() > 1
@@ -1862,7 +1948,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
                         module.res().unwrap()
                     }
-                    _ => return Some(result),
+                    _ => return Ok(Some(result)),
                 }
             };
             if result.base_res() == unqualified_result {
@@ -1871,7 +1957,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             }
         }
 
-        Some(result)
+        Ok(Some(result))
     }
 
     fn with_resolved_label(&mut self, label: Option<Label>, id: NodeId, f: impl FnOnce(&mut Self)) {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index e5fc23e14d2..c7f10fac6bc 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -618,13 +618,13 @@ struct PrivacyError<'a> {
 
 struct UseError<'a> {
     err: DiagnosticBuilder<'a>,
-    /// Attach `use` statements for these candidates.
+    /// Candidates which user could `use` to access the missing type.
     candidates: Vec<ImportSuggestion>,
-    /// The `NodeId` of the module to place the use-statements in.
+    /// The `DefId` of the module to place the use-statements in.
     def_id: DefId,
-    /// Whether the diagnostic should state that it's "better".
-    better: bool,
-    /// Extra free form suggestion. Currently used to suggest new type parameter.
+    /// Whether the diagnostic should say "instead" (as in `consider importing ... instead`).
+    instead: bool,
+    /// Extra free-form suggestion.
     suggestion: Option<(Span, &'static str, String, Applicability)>,
 }
 
@@ -2577,12 +2577,12 @@ impl<'a> Resolver<'a> {
     }
 
     fn report_with_use_injections(&mut self, krate: &Crate) {
-        for UseError { mut err, candidates, def_id, better, suggestion } in
+        for UseError { mut err, candidates, def_id, instead, suggestion } in
             self.use_injections.drain(..)
         {
             let (span, found_use) = UsePlacementFinder::check(&self.definitions, krate, def_id);
             if !candidates.is_empty() {
-                diagnostics::show_candidates(&mut err, span, &candidates, better, found_use);
+                diagnostics::show_candidates(&mut err, span, &candidates, instead, found_use);
             } else if let Some((span, msg, sugg, appl)) = suggestion {
                 err.span_suggestion(span, msg, sugg, appl);
             }
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 3dd715f9e3d..a5e61ab9ab0 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -13,19 +13,19 @@
 //! DumpVisitor walks the AST and processes it, and Dumper is used for
 //! recording the output.
 
-use rustc_ast::ast::{self, Attribute, NodeId, PatKind};
-use rustc_ast::ptr::P;
-use rustc_ast::token;
-use rustc_ast::visit::{self, Visitor};
-use rustc_ast::walk_list;
-use rustc_ast_pretty::pprust::{bounds_to_string, generic_params_to_string, ty_to_string};
+use rustc_ast::ast::{self};
+use rustc_ast::{token, walk_list};
 use rustc_data_structures::fx::FxHashSet;
+use rustc_hir as hir;
 use rustc_hir::def::{DefKind as HirDefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir_pretty::{bounds_to_string, generic_params_to_string, ty_to_string};
+use rustc_middle::hir::map::Map;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_session::config::Input;
-use rustc_span::source_map::{respan, DUMMY_SP};
+use rustc_span::source_map::respan;
 use rustc_span::symbol::Ident;
 use rustc_span::*;
 
@@ -36,7 +36,7 @@ use crate::dumper::{Access, Dumper};
 use crate::sig;
 use crate::span_utils::SpanUtils;
 use crate::{
-    escape, generated_code, id_from_def_id, id_from_node_id, lower_attributes, PathCollector,
+    escape, generated_code, id_from_def_id, id_from_hir_id, lower_attributes, PathCollector,
     SaveContext,
 };
 
@@ -124,11 +124,11 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         self.save_ctxt.span_from_span(span)
     }
 
-    fn lookup_def_id(&self, ref_id: NodeId) -> Option<DefId> {
+    fn lookup_def_id(&self, ref_id: hir::HirId) -> Option<DefId> {
         self.save_ctxt.lookup_def_id(ref_id)
     }
 
-    pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) {
+    pub fn dump_crate_info(&mut self, name: &str, krate: &hir::Crate<'_>) {
         let source_file = self.tcx.sess.local_crate_source_file.as_ref();
         let crate_root = source_file.map(|source_file| {
             let source_file = Path::new(source_file);
@@ -151,7 +151,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
             },
             crate_root: crate_root.unwrap_or_else(|| "<no source>".to_owned()),
             external_crates: self.save_ctxt.get_external_crates(),
-            span: self.span_from_span(krate.span),
+            span: self.span_from_span(krate.item.span),
         };
 
         self.dumper.crate_prelude(data);
@@ -199,8 +199,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         self.dumper.compilation_opts(data);
     }
 
-    fn write_sub_paths(&mut self, path: &ast::Path) {
-        for seg in &path.segments {
+    fn write_sub_paths(&mut self, path: &'tcx hir::Path<'tcx>) {
+        for seg in path.segments {
             if let Some(data) = self.save_ctxt.get_path_segment_data(seg) {
                 self.dumper.dump_ref(data);
             }
@@ -209,7 +209,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
 
     // As write_sub_paths, but does not process the last ident in the path (assuming it
     // will be processed elsewhere). See note on write_sub_paths about global.
-    fn write_sub_paths_truncated(&mut self, path: &ast::Path) {
+    fn write_sub_paths_truncated(&mut self, path: &'tcx hir::Path<'tcx>) {
         for seg in &path.segments[..path.segments.len() - 1] {
             if let Some(data) = self.save_ctxt.get_path_segment_data(seg) {
                 self.dumper.dump_ref(data);
@@ -217,23 +217,19 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         }
     }
 
-    fn process_formals(&mut self, formals: &'l [ast::Param], qualname: &str) {
+    fn process_formals(&mut self, formals: &'tcx [hir::Param<'tcx>], qualname: &str) {
         for arg in formals {
             self.visit_pat(&arg.pat);
-            let mut collector = PathCollector::new();
+            let mut collector = PathCollector::new(self.tcx);
             collector.visit_pat(&arg.pat);
 
-            for (id, ident, ..) in collector.collected_idents {
-                // FIXME(#71104) Should really be using just `node_id_to_hir_id` but
-                // some `NodeId` do not seem to have a corresponding HirId.
-                let hir_id = self.tcx.hir().opt_node_id_to_hir_id(id);
-                let typ =
-                    match hir_id.and_then(|hir_id| self.save_ctxt.tables.node_type_opt(hir_id)) {
-                        Some(s) => s.to_string(),
-                        None => continue,
-                    };
+            for (hir_id, ident, ..) in collector.collected_idents {
+                let typ = match self.save_ctxt.tables.node_type_opt(hir_id) {
+                    Some(s) => s.to_string(),
+                    None => continue,
+                };
                 if !self.span.filter_generated(ident.span) {
-                    let id = id_from_node_id(id, &self.save_ctxt);
+                    let id = id_from_hir_id(hir_id, &self.save_ctxt);
                     let span = self.span_from_span(ident.span);
 
                     self.dumper.dump_def(
@@ -260,75 +256,74 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
 
     fn process_method(
         &mut self,
-        sig: &'l ast::FnSig,
-        body: Option<&'l ast::Block>,
-        id: ast::NodeId,
+        sig: &'tcx hir::FnSig<'tcx>,
+        body: Option<hir::BodyId>,
+        hir_id: hir::HirId,
         ident: Ident,
-        generics: &'l ast::Generics,
-        vis: ast::Visibility,
+        generics: &'tcx hir::Generics<'tcx>,
+        vis: &hir::Visibility<'tcx>,
         span: Span,
     ) {
-        debug!("process_method: {}:{}", id, ident);
+        debug!("process_method: {}:{}", hir_id, ident);
 
         let map = &self.tcx.hir();
-        let hir_id = map.node_id_to_hir_id(id);
         self.nest_tables(map.local_def_id(hir_id), |v| {
-            if let Some(mut method_data) = v.save_ctxt.get_method_data(id, ident, span) {
-                v.process_formals(&sig.decl.inputs, &method_data.qualname);
-                v.process_generic_params(&generics, &method_data.qualname, id);
+            if let Some(mut method_data) = v.save_ctxt.get_method_data(hir_id, ident, span) {
+                if let Some(body) = body {
+                    v.process_formals(map.body(body).params, &method_data.qualname);
+                }
+                v.process_generic_params(&generics, &method_data.qualname, hir_id);
 
                 method_data.value = crate::make_signature(&sig.decl, &generics);
-                method_data.sig = sig::method_signature(id, ident, generics, sig, &v.save_ctxt);
+                method_data.sig = sig::method_signature(hir_id, ident, generics, sig, &v.save_ctxt);
 
                 v.dumper.dump_def(&access_from_vis!(v.save_ctxt, vis, hir_id), method_data);
             }
 
             // walk arg and return types
-            for arg in &sig.decl.inputs {
-                v.visit_ty(&arg.ty);
+            for arg in sig.decl.inputs {
+                v.visit_ty(arg);
             }
 
-            if let ast::FnRetTy::Ty(ref ret_ty) = sig.decl.output {
-                // In async functions, return types are desugared and redefined
-                // as an `impl Trait` existential type. Because of this, to match
-                // the definition paths when resolving nested types we need to
-                // start walking from the newly-created definition.
-                match sig.header.asyncness {
-                    ast::Async::Yes { return_impl_trait_id, .. } => {
-                        let hir_id = map.node_id_to_hir_id(return_impl_trait_id);
-                        v.nest_tables(map.local_def_id(hir_id), |v| v.visit_ty(ret_ty))
-                    }
-                    _ => v.visit_ty(ret_ty),
-                }
+            if let hir::FnRetTy::Return(ref ret_ty) = sig.decl.output {
+                v.visit_ty(ret_ty)
             }
 
             // walk the fn body
             if let Some(body) = body {
-                v.visit_block(body);
+                v.visit_expr(&map.body(body).value);
             }
         });
     }
 
-    fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) {
+    fn process_struct_field_def(
+        &mut self,
+        field: &'tcx hir::StructField<'tcx>,
+        parent_id: hir::HirId,
+    ) {
         let field_data = self.save_ctxt.get_field_data(field, parent_id);
         if let Some(field_data) = field_data {
-            let hir_id = self.tcx.hir().node_id_to_hir_id(field.id);
-            self.dumper.dump_def(&access_from!(self.save_ctxt, field, hir_id), field_data);
+            self.dumper.dump_def(&access_from!(self.save_ctxt, field, field.hir_id), field_data);
         }
     }
 
     // Dump generic params bindings, then visit_generics
-    fn process_generic_params(&mut self, generics: &'l ast::Generics, prefix: &str, id: NodeId) {
-        for param in &generics.params {
+    fn process_generic_params(
+        &mut self,
+        generics: &'tcx hir::Generics<'tcx>,
+        prefix: &str,
+        id: hir::HirId,
+    ) {
+        for param in generics.params {
             match param.kind {
-                ast::GenericParamKind::Lifetime { .. } => {}
-                ast::GenericParamKind::Type { .. } => {
-                    let param_ss = param.ident.span;
+                hir::GenericParamKind::Lifetime { .. } => {}
+                hir::GenericParamKind::Type { .. } => {
+                    let param_ss = param.name.ident().span;
                     let name = escape(self.span.snippet(param_ss));
                     // Append $id to name to make sure each one is unique.
                     let qualname = format!("{}::{}${}", prefix, name, id);
                     if !self.span.filter_generated(param_ss) {
-                        let id = id_from_node_id(param.id, &self.save_ctxt);
+                        let id = id_from_hir_id(param.hir_id, &self.save_ctxt);
                         let span = self.span_from_span(param_ss);
 
                         self.dumper.dump_def(
@@ -350,7 +345,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                         );
                     }
                 }
-                ast::GenericParamKind::Const { .. } => {}
+                hir::GenericParamKind::Const { .. } => {}
             }
         }
         self.visit_generics(generics);
@@ -358,90 +353,73 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
 
     fn process_fn(
         &mut self,
-        item: &'l ast::Item,
-        decl: &'l ast::FnDecl,
-        header: &'l ast::FnHeader,
-        ty_params: &'l ast::Generics,
-        body: Option<&'l ast::Block>,
+        item: &'tcx hir::Item<'tcx>,
+        decl: &'tcx hir::FnDecl<'tcx>,
+        _header: &'tcx hir::FnHeader,
+        ty_params: &'tcx hir::Generics<'tcx>,
+        body: hir::BodyId,
     ) {
         let map = &self.tcx.hir();
-        let hir_id = map.node_id_to_hir_id(item.id);
-        self.nest_tables(map.local_def_id(hir_id), |v| {
+        self.nest_tables(map.local_def_id(item.hir_id), |v| {
+            let body = map.body(body);
             if let Some(fn_data) = v.save_ctxt.get_item_data(item) {
                 down_cast_data!(fn_data, DefData, item.span);
-                v.process_formals(&decl.inputs, &fn_data.qualname);
-                v.process_generic_params(ty_params, &fn_data.qualname, item.id);
+                v.process_formals(body.params, &fn_data.qualname);
+                v.process_generic_params(ty_params, &fn_data.qualname, item.hir_id);
 
-                v.dumper.dump_def(&access_from!(v.save_ctxt, item, hir_id), fn_data);
+                v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.hir_id), fn_data);
             }
 
-            for arg in &decl.inputs {
-                v.visit_ty(&arg.ty)
+            for arg in decl.inputs {
+                v.visit_ty(arg)
             }
 
-            if let ast::FnRetTy::Ty(ref ret_ty) = decl.output {
-                if let ast::TyKind::ImplTrait(..) = ret_ty.kind {
-                    // FIXME: Opaque type desugaring prevents us from easily
-                    // processing trait bounds. See `visit_ty` for more details.
-                } else {
-                    // In async functions, return types are desugared and redefined
-                    // as an `impl Trait` existential type. Because of this, to match
-                    // the definition paths when resolving nested types we need to
-                    // start walking from the newly-created definition.
-                    match header.asyncness {
-                        ast::Async::Yes { return_impl_trait_id, .. } => {
-                            let hir_id = map.node_id_to_hir_id(return_impl_trait_id);
-                            v.nest_tables(map.local_def_id(hir_id), |v| v.visit_ty(ret_ty))
-                        }
-                        _ => v.visit_ty(ret_ty),
-                    }
-                }
+            if let hir::FnRetTy::Return(ref ret_ty) = decl.output {
+                v.visit_ty(ret_ty)
             }
 
-            walk_list!(v, visit_block, body);
+            v.visit_expr(&body.value);
         });
     }
 
     fn process_static_or_const_item(
         &mut self,
-        item: &'l ast::Item,
-        typ: &'l ast::Ty,
-        expr: Option<&'l ast::Expr>,
+        item: &'tcx hir::Item<'tcx>,
+        typ: &'tcx hir::Ty<'tcx>,
+        expr: &'tcx hir::Expr<'tcx>,
     ) {
-        let hir_id = self.tcx.hir().node_id_to_hir_id(item.id);
-        self.nest_tables(self.tcx.hir().local_def_id(hir_id), |v| {
+        self.nest_tables(self.tcx.hir().local_def_id(item.hir_id), |v| {
             if let Some(var_data) = v.save_ctxt.get_item_data(item) {
                 down_cast_data!(var_data, DefData, item.span);
-                v.dumper.dump_def(&access_from!(v.save_ctxt, item, hir_id), var_data);
+                v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.hir_id), var_data);
             }
             v.visit_ty(&typ);
-            walk_list!(v, visit_expr, expr);
+            v.visit_expr(expr);
         });
     }
 
     fn process_assoc_const(
         &mut self,
-        id: ast::NodeId,
+        hir_id: hir::HirId,
         ident: Ident,
-        typ: &'l ast::Ty,
-        expr: Option<&'l ast::Expr>,
+        typ: &'tcx hir::Ty<'tcx>,
+        expr: Option<&'tcx hir::Expr<'tcx>>,
         parent_id: DefId,
-        vis: ast::Visibility,
-        attrs: &'l [Attribute],
+        vis: &hir::Visibility<'tcx>,
+        attrs: &'tcx [ast::Attribute],
     ) {
-        let hir_id = self.tcx.hir().node_id_to_hir_id(id);
         let qualname =
             format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id(hir_id).to_def_id()));
 
         if !self.span.filter_generated(ident.span) {
-            let sig = sig::assoc_const_signature(id, ident.name, typ, expr, &self.save_ctxt);
+            let sig = sig::assoc_const_signature(hir_id, ident.name, typ, expr, &self.save_ctxt);
             let span = self.span_from_span(ident.span);
 
             self.dumper.dump_def(
                 &access_from_vis!(self.save_ctxt, vis, hir_id),
                 Def {
                     kind: DefKind::Const,
-                    id: id_from_node_id(id, &self.save_ctxt),
+                    id: id_from_hir_id(hir_id, &self.save_ctxt),
                     span,
                     name: ident.name.to_string(),
                     qualname,
@@ -468,32 +446,32 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
     // FIXME tuple structs should generate tuple-specific data.
     fn process_struct(
         &mut self,
-        item: &'l ast::Item,
-        def: &'l ast::VariantData,
-        ty_params: &'l ast::Generics,
+        item: &'tcx hir::Item<'tcx>,
+        def: &'tcx hir::VariantData<'tcx>,
+        ty_params: &'tcx hir::Generics<'tcx>,
     ) {
         debug!("process_struct {:?} {:?}", item, item.span);
         let name = item.ident.to_string();
-        let hir_id = self.tcx.hir().node_id_to_hir_id(item.id);
-        let qualname =
-            format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id(hir_id).to_def_id()));
+        let qualname = format!(
+            "::{}",
+            self.tcx.def_path_str(self.tcx.hir().local_def_id(item.hir_id).to_def_id())
+        );
 
         let kind = match item.kind {
-            ast::ItemKind::Struct(_, _) => DefKind::Struct,
-            ast::ItemKind::Union(_, _) => DefKind::Union,
+            hir::ItemKind::Struct(_, _) => DefKind::Struct,
+            hir::ItemKind::Union(_, _) => DefKind::Union,
             _ => unreachable!(),
         };
 
         let (value, fields) = match item.kind {
-            ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, ..), ..)
-            | ast::ItemKind::Union(ast::VariantData::Struct(ref fields, ..), ..) => {
+            hir::ItemKind::Struct(hir::VariantData::Struct(ref fields, ..), ..)
+            | hir::ItemKind::Union(hir::VariantData::Struct(ref fields, ..), ..) => {
                 let include_priv_fields = !self.save_ctxt.config.pub_only;
                 let fields_str = fields
                     .iter()
-                    .enumerate()
-                    .filter_map(|(i, f)| {
+                    .filter_map(|f| {
                         if include_priv_fields || f.vis.node.is_pub() {
-                            f.ident.map(|i| i.to_string()).or_else(|| Some(i.to_string()))
+                            Some(f.ident.to_string())
                         } else {
                             None
                         }
@@ -501,7 +479,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     .collect::<Vec<_>>()
                     .join(", ");
                 let value = format!("{} {{ {} }}", name, fields_str);
-                (value, fields.iter().map(|f| id_from_node_id(f.id, &self.save_ctxt)).collect())
+                (value, fields.iter().map(|f| id_from_hir_id(f.hir_id, &self.save_ctxt)).collect())
             }
             _ => (String::new(), vec![]),
         };
@@ -509,10 +487,10 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         if !self.span.filter_generated(item.ident.span) {
             let span = self.span_from_span(item.ident.span);
             self.dumper.dump_def(
-                &access_from!(self.save_ctxt, item, hir_id),
+                &access_from!(self.save_ctxt, item, item.hir_id),
                 Def {
                     kind,
-                    id: id_from_node_id(item.id, &self.save_ctxt),
+                    id: id_from_hir_id(item.hir_id, &self.save_ctxt),
                     span,
                     name,
                     qualname: qualname.clone(),
@@ -522,26 +500,26 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     decl_id: None,
                     docs: self.save_ctxt.docs_for_attrs(&item.attrs),
                     sig: sig::item_signature(item, &self.save_ctxt),
-                    attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
+                    attributes: lower_attributes(item.attrs.to_vec(), &self.save_ctxt),
                 },
             );
         }
 
-        self.nest_tables(self.tcx.hir().local_def_id(hir_id), |v| {
+        self.nest_tables(self.tcx.hir().local_def_id(item.hir_id), |v| {
             for field in def.fields() {
-                v.process_struct_field_def(field, item.id);
+                v.process_struct_field_def(field, item.hir_id);
                 v.visit_ty(&field.ty);
             }
 
-            v.process_generic_params(ty_params, &qualname, item.id);
+            v.process_generic_params(ty_params, &qualname, item.hir_id);
         });
     }
 
     fn process_enum(
         &mut self,
-        item: &'l ast::Item,
-        enum_definition: &'l ast::EnumDef,
-        ty_params: &'l ast::Generics,
+        item: &'tcx hir::Item<'tcx>,
+        enum_definition: &'tcx hir::EnumDef<'tcx>,
+        ty_params: &'tcx hir::Generics<'tcx>,
     ) {
         let enum_data = self.save_ctxt.get_item_data(item);
         let enum_data = match enum_data {
@@ -550,29 +528,22 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         };
         down_cast_data!(enum_data, DefData, item.span);
 
-        let hir_id = self.tcx.hir().node_id_to_hir_id(item.id);
-        let access = access_from!(self.save_ctxt, item, hir_id);
+        let access = access_from!(self.save_ctxt, item, item.hir_id);
 
-        for variant in &enum_definition.variants {
+        for variant in enum_definition.variants {
             let name = variant.ident.name.to_string();
             let qualname = format!("{}::{}", enum_data.qualname, name);
             let name_span = variant.ident.span;
 
             match variant.data {
-                ast::VariantData::Struct(ref fields, ..) => {
-                    let fields_str = fields
-                        .iter()
-                        .enumerate()
-                        .map(|(i, f)| {
-                            f.ident.map(|i| i.to_string()).unwrap_or_else(|| i.to_string())
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ");
+                hir::VariantData::Struct(ref fields, ..) => {
+                    let fields_str =
+                        fields.iter().map(|f| f.ident.to_string()).collect::<Vec<_>>().join(", ");
                     let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str);
                     if !self.span.filter_generated(name_span) {
                         let span = self.span_from_span(name_span);
-                        let id = id_from_node_id(variant.id, &self.save_ctxt);
-                        let parent = Some(id_from_node_id(item.id, &self.save_ctxt));
+                        let id = id_from_hir_id(variant.id, &self.save_ctxt);
+                        let parent = Some(id_from_hir_id(item.hir_id, &self.save_ctxt));
 
                         self.dumper.dump_def(
                             &access,
@@ -589,7 +560,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                                 docs: self.save_ctxt.docs_for_attrs(&variant.attrs),
                                 sig: sig::variant_signature(variant, &self.save_ctxt),
                                 attributes: lower_attributes(
-                                    variant.attrs.clone(),
+                                    variant.attrs.to_vec(),
                                     &self.save_ctxt,
                                 ),
                             },
@@ -598,7 +569,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                 }
                 ref v => {
                     let mut value = format!("{}::{}", enum_data.name, name);
-                    if let &ast::VariantData::Tuple(ref fields, _) = v {
+                    if let &hir::VariantData::Tuple(ref fields, _) = v {
                         value.push('(');
                         value.push_str(
                             &fields
@@ -611,8 +582,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     }
                     if !self.span.filter_generated(name_span) {
                         let span = self.span_from_span(name_span);
-                        let id = id_from_node_id(variant.id, &self.save_ctxt);
-                        let parent = Some(id_from_node_id(item.id, &self.save_ctxt));
+                        let id = id_from_hir_id(variant.id, &self.save_ctxt);
+                        let parent = Some(id_from_hir_id(item.hir_id, &self.save_ctxt));
 
                         self.dumper.dump_def(
                             &access,
@@ -629,7 +600,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                                 docs: self.save_ctxt.docs_for_attrs(&variant.attrs),
                                 sig: sig::variant_signature(variant, &self.save_ctxt),
                                 attributes: lower_attributes(
-                                    variant.attrs.clone(),
+                                    variant.attrs.to_vec(),
                                     &self.save_ctxt,
                                 ),
                             },
@@ -640,20 +611,20 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
 
             for field in variant.data.fields() {
                 self.process_struct_field_def(field, variant.id);
-                self.visit_ty(&field.ty);
+                self.visit_ty(field.ty);
             }
         }
-        self.process_generic_params(ty_params, &enum_data.qualname, item.id);
+        self.process_generic_params(ty_params, &enum_data.qualname, item.hir_id);
         self.dumper.dump_def(&access, enum_data);
     }
 
     fn process_impl(
         &mut self,
-        item: &'l ast::Item,
-        generics: &'l ast::Generics,
-        trait_ref: &'l Option<ast::TraitRef>,
-        typ: &'l ast::Ty,
-        impl_items: &'l [P<ast::AssocItem>],
+        item: &'tcx hir::Item<'tcx>,
+        generics: &'tcx hir::Generics<'tcx>,
+        trait_ref: &'tcx Option<hir::TraitRef<'tcx>>,
+        typ: &'tcx hir::Ty<'tcx>,
+        impl_items: &'tcx [hir::ImplItemRef<'tcx>],
     ) {
         if let Some(impl_data) = self.save_ctxt.get_item_data(item) {
             if !self.span.filter_generated(item.span) {
@@ -667,46 +638,48 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         }
 
         let map = &self.tcx.hir();
-        let hir_id = map.node_id_to_hir_id(item.id);
-        self.nest_tables(map.local_def_id(hir_id), |v| {
+        self.nest_tables(map.local_def_id(item.hir_id), |v| {
             v.visit_ty(&typ);
             if let &Some(ref trait_ref) = trait_ref {
-                v.process_path(trait_ref.ref_id, &trait_ref.path);
+                v.process_path(trait_ref.hir_ref_id, &trait_ref.path);
             }
-            v.process_generic_params(generics, "", item.id);
+            v.process_generic_params(generics, "", item.hir_id);
             for impl_item in impl_items {
-                v.process_impl_item(impl_item, map.local_def_id(hir_id).to_def_id());
+                v.process_impl_item(
+                    map.impl_item(impl_item.id),
+                    map.local_def_id(item.hir_id).to_def_id(),
+                );
             }
         });
     }
 
     fn process_trait(
         &mut self,
-        item: &'l ast::Item,
-        generics: &'l ast::Generics,
-        trait_refs: &'l ast::GenericBounds,
-        methods: &'l [P<ast::AssocItem>],
+        item: &'tcx hir::Item<'tcx>,
+        generics: &'tcx hir::Generics<'tcx>,
+        trait_refs: hir::GenericBounds<'tcx>,
+        methods: &'tcx [hir::TraitItemRef],
     ) {
         let name = item.ident.to_string();
         let qualname = format!(
             "::{}",
-            self.tcx.def_path_str(self.tcx.hir().local_def_id_from_node_id(item.id).to_def_id())
+            self.tcx.def_path_str(self.tcx.hir().local_def_id(item.hir_id).to_def_id())
         );
         let mut val = name.clone();
         if !generics.params.is_empty() {
-            val.push_str(&generic_params_to_string(&generics.params));
+            val.push_str(&generic_params_to_string(generics.params));
         }
         if !trait_refs.is_empty() {
             val.push_str(": ");
             val.push_str(&bounds_to_string(trait_refs));
         }
         if !self.span.filter_generated(item.ident.span) {
-            let id = id_from_node_id(item.id, &self.save_ctxt);
+            let id = id_from_hir_id(item.hir_id, &self.save_ctxt);
             let span = self.span_from_span(item.ident.span);
-            let children = methods.iter().map(|i| id_from_node_id(i.id, &self.save_ctxt)).collect();
-            let hir_id = self.tcx.hir().node_id_to_hir_id(item.id);
+            let children =
+                methods.iter().map(|i| id_from_hir_id(i.id.hir_id, &self.save_ctxt)).collect();
             self.dumper.dump_def(
-                &access_from!(self.save_ctxt, item, hir_id),
+                &access_from!(self.save_ctxt, item, item.hir_id),
                 Def {
                     kind: DefKind::Trait,
                     id,
@@ -719,7 +692,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     decl_id: None,
                     docs: self.save_ctxt.docs_for_attrs(&item.attrs),
                     sig: sig::item_signature(item, &self.save_ctxt),
-                    attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
+                    attributes: lower_attributes(item.attrs.to_vec(), &self.save_ctxt),
                 },
             );
         }
@@ -727,12 +700,12 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         // super-traits
         for super_bound in trait_refs.iter() {
             let trait_ref = match *super_bound {
-                ast::GenericBound::Trait(ref trait_ref, _) => trait_ref,
-                ast::GenericBound::Outlives(..) => continue,
+                hir::GenericBound::Trait(ref trait_ref, _) => trait_ref,
+                hir::GenericBound::Outlives(..) => continue,
             };
 
             let trait_ref = &trait_ref.trait_ref;
-            if let Some(id) = self.lookup_def_id(trait_ref.ref_id) {
+            if let Some(id) = self.lookup_def_id(trait_ref.hir_ref_id) {
                 let sub_span = trait_ref.path.segments.last().unwrap().ident.span;
                 if !self.span.filter_generated(sub_span) {
                     let span = self.span_from_span(sub_span);
@@ -746,60 +719,57 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                         kind: RelationKind::SuperTrait,
                         span,
                         from: id_from_def_id(id),
-                        to: id_from_node_id(item.id, &self.save_ctxt),
+                        to: id_from_hir_id(item.hir_id, &self.save_ctxt),
                     });
                 }
             }
         }
 
         // walk generics and methods
-        self.process_generic_params(generics, &qualname, item.id);
+        self.process_generic_params(generics, &qualname, item.hir_id);
         for method in methods {
             let map = &self.tcx.hir();
-            self.process_trait_item(method, map.local_def_id_from_node_id(item.id).to_def_id())
+            self.process_trait_item(
+                map.trait_item(method.id),
+                map.local_def_id(item.hir_id).to_def_id(),
+            )
         }
     }
 
-    // `item` is the module in question, represented as an item.
-    fn process_mod(&mut self, item: &ast::Item) {
+    // `item` is the module in question, represented as an( item.
+    fn process_mod(&mut self, item: &'tcx hir::Item<'tcx>) {
         if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
             down_cast_data!(mod_data, DefData, item.span);
-            let hir_id = self.tcx.hir().node_id_to_hir_id(item.id);
-            self.dumper.dump_def(&access_from!(self.save_ctxt, item, hir_id), mod_data);
+            self.dumper.dump_def(&access_from!(self.save_ctxt, item, item.hir_id), mod_data);
         }
     }
 
-    fn dump_path_ref(&mut self, id: NodeId, path: &ast::Path) {
+    fn dump_path_ref(&mut self, id: hir::HirId, path: &hir::Path<'tcx>) {
         let path_data = self.save_ctxt.get_path_data(id, path);
         if let Some(path_data) = path_data {
             self.dumper.dump_ref(path_data);
         }
     }
 
-    fn process_path(&mut self, id: NodeId, path: &'l ast::Path) {
+    fn dump_path_segment_ref(&mut self, id: hir::HirId, segment: &hir::PathSegment<'tcx>) {
+        let segment_data = self.save_ctxt.get_path_segment_data_with_id(segment, id);
+        if let Some(segment_data) = segment_data {
+            self.dumper.dump_ref(segment_data);
+        }
+    }
+
+    fn process_path(&mut self, id: hir::HirId, path: &'tcx hir::Path<'tcx>) {
         if self.span.filter_generated(path.span) {
             return;
         }
         self.dump_path_ref(id, path);
 
         // Type arguments
-        for seg in &path.segments {
+        for seg in path.segments {
             if let Some(ref generic_args) = seg.args {
-                match **generic_args {
-                    ast::GenericArgs::AngleBracketed(ref data) => {
-                        for arg in &data.args {
-                            if let ast::AngleBracketedArg::Arg(ast::GenericArg::Type(ty)) = arg {
-                                self.visit_ty(ty);
-                            }
-                        }
-                    }
-                    ast::GenericArgs::Parenthesized(ref data) => {
-                        for t in &data.inputs {
-                            self.visit_ty(t);
-                        }
-                        if let ast::FnRetTy::Ty(ty) = &data.output {
-                            self.visit_ty(ty);
-                        }
+                for arg in generic_args.args {
+                    if let hir::GenericArg::Type(ref ty) = arg {
+                        self.visit_ty(ty);
                     }
                 }
             }
@@ -810,14 +780,16 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
 
     fn process_struct_lit(
         &mut self,
-        ex: &'l ast::Expr,
-        path: &'l ast::Path,
-        fields: &'l [ast::Field],
-        variant: &'l ty::VariantDef,
-        base: &'l Option<P<ast::Expr>>,
+        ex: &'tcx hir::Expr<'tcx>,
+        path: &'tcx hir::QPath<'tcx>,
+        fields: &'tcx [hir::Field<'tcx>],
+        variant: &'tcx ty::VariantDef,
+        base: Option<&'tcx hir::Expr<'tcx>>,
     ) {
         if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
-            self.write_sub_paths_truncated(path);
+            if let hir::QPath::Resolved(_, path) = path {
+                self.write_sub_paths_truncated(path);
+            }
             down_cast_data!(struct_lit_data, RefData, ex.span);
             if !generated_code(ex.span) {
                 self.dumper.dump_ref(struct_lit_data);
@@ -837,9 +809,9 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
 
     fn process_method_call(
         &mut self,
-        ex: &'l ast::Expr,
-        seg: &'l ast::PathSegment,
-        args: &'l [P<ast::Expr>],
+        ex: &'tcx hir::Expr<'tcx>,
+        seg: &'tcx hir::PathSegment<'tcx>,
+        args: &'tcx [hir::Expr<'tcx>],
     ) {
         debug!("process_method_call {:?} {:?}", ex, ex.span);
         if let Some(mcd) = self.save_ctxt.get_expr_data(ex) {
@@ -850,13 +822,11 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         }
 
         // Explicit types in the turbo-fish.
-        if let Some(ref generic_args) = seg.args {
-            if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args {
-                for arg in &data.args {
-                    if let ast::AngleBracketedArg::Arg(ast::GenericArg::Type(ty)) = arg {
-                        self.visit_ty(ty)
-                    };
-                }
+        if let Some(generic_args) = seg.args {
+            for arg in generic_args.args {
+                if let hir::GenericArg::Type(ty) = arg {
+                    self.visit_ty(&ty)
+                };
             }
         }
 
@@ -864,19 +834,18 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         walk_list!(self, visit_expr, args);
     }
 
-    fn process_pat(&mut self, p: &'l ast::Pat) {
+    fn process_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
         match p.kind {
-            PatKind::Struct(ref _path, ref fields, _) => {
+            hir::PatKind::Struct(ref _path, fields, _) => {
                 // FIXME do something with _path?
-                let hir_id = self.tcx.hir().node_id_to_hir_id(p.id);
-                let adt = match self.save_ctxt.tables.node_type_opt(hir_id) {
+                let adt = match self.save_ctxt.tables.node_type_opt(p.hir_id) {
                     Some(ty) if ty.ty_adt_def().is_some() => ty.ty_adt_def().unwrap(),
                     _ => {
-                        visit::walk_pat(self, p);
+                        intravisit::walk_pat(self, p);
                         return;
                     }
                 };
-                let variant = adt.variant_of_res(self.save_ctxt.get_path_res(p.id));
+                let variant = adt.variant_of_res(self.save_ctxt.get_path_res(p.hir_id));
 
                 for field in fields {
                     if let Some(index) = self.tcx.find_field_index(field.ident, variant) {
@@ -892,22 +861,22 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     self.visit_pat(&field.pat);
                 }
             }
-            _ => visit::walk_pat(self, p),
+            _ => intravisit::walk_pat(self, p),
         }
     }
 
-    fn process_var_decl(&mut self, pat: &'l ast::Pat) {
+    fn process_var_decl(&mut self, pat: &'tcx hir::Pat<'tcx>) {
         // The pattern could declare multiple new vars,
         // we must walk the pattern and collect them all.
-        let mut collector = PathCollector::new();
+        let mut collector = PathCollector::new(self.tcx);
         collector.visit_pat(&pat);
         self.visit_pat(&pat);
 
         // Process collected paths.
         for (id, ident, _) in collector.collected_idents {
-            match self.save_ctxt.get_path_res(id) {
+            let res = self.save_ctxt.get_path_res(id);
+            match res {
                 Res::Local(hir_id) => {
-                    let id = self.tcx.hir().hir_id_to_node_id(hir_id);
                     let typ = self
                         .save_ctxt
                         .tables
@@ -917,8 +886,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
 
                     // Rust uses the id of the pattern for var lookups, so we'll use it too.
                     if !self.span.filter_generated(ident.span) {
-                        let qualname = format!("{}${}", ident.to_string(), id);
-                        let id = id_from_node_id(id, &self.save_ctxt);
+                        let qualname = format!("{}${}", ident.to_string(), hir_id);
+                        let id = id_from_hir_id(hir_id, &self.save_ctxt);
                         let span = self.span_from_span(ident.span);
 
                         self.dumper.dump_def(
@@ -951,7 +920,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     _,
                 )
                 | Res::SelfTy(..) => {
-                    self.dump_path_ref(id, &ast::Path::from_ident(ident));
+                    self.dump_path_segment_ref(id, &hir::PathSegment::from_ident(ident));
                 }
                 def => {
                     error!("unexpected definition kind when processing collected idents: {:?}", def)
@@ -960,7 +929,9 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         }
 
         for (id, ref path) in collector.collected_paths {
-            self.process_path(id, path);
+            if let hir::QPath::Resolved(_, path) = path {
+                self.process_path(id, path);
+            }
         }
     }
 
@@ -1007,45 +978,49 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         // }
     }
 
-    fn process_trait_item(&mut self, trait_item: &'l ast::AssocItem, trait_id: DefId) {
+    fn process_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>, trait_id: DefId) {
         self.process_macro_use(trait_item.span);
         let vis_span = trait_item.span.shrink_to_lo();
         match trait_item.kind {
-            ast::AssocItemKind::Const(_, ref ty, ref expr) => {
+            hir::TraitItemKind::Const(ref ty, body) => {
+                let body = body.map(|b| &self.tcx.hir().body(b).value);
+                let respan = respan(vis_span, hir::VisibilityKind::Public);
                 self.process_assoc_const(
-                    trait_item.id,
+                    trait_item.hir_id,
                     trait_item.ident,
                     &ty,
-                    expr.as_ref().map(|e| &**e),
+                    body,
                     trait_id,
-                    respan(vis_span, ast::VisibilityKind::Public),
+                    &respan,
                     &trait_item.attrs,
                 );
             }
-            ast::AssocItemKind::Fn(_, ref sig, ref generics, ref body) => {
+            hir::TraitItemKind::Fn(ref sig, ref trait_fn) => {
+                let body =
+                    if let hir::TraitFn::Provided(body) = trait_fn { Some(*body) } else { None };
+                let respan = respan(vis_span, hir::VisibilityKind::Public);
                 self.process_method(
                     sig,
-                    body.as_ref().map(|x| &**x),
-                    trait_item.id,
+                    body,
+                    trait_item.hir_id,
                     trait_item.ident,
-                    generics,
-                    respan(vis_span, ast::VisibilityKind::Public),
+                    &trait_item.generics,
+                    &respan,
                     trait_item.span,
                 );
             }
-            ast::AssocItemKind::TyAlias(_, _, ref bounds, ref default_ty) => {
+            hir::TraitItemKind::Type(ref bounds, ref default_ty) => {
                 // FIXME do something with _bounds (for type refs)
                 let name = trait_item.ident.name.to_string();
                 let qualname = format!(
                     "::{}",
-                    self.tcx.def_path_str(
-                        self.tcx.hir().local_def_id_from_node_id(trait_item.id).to_def_id()
-                    )
+                    self.tcx
+                        .def_path_str(self.tcx.hir().local_def_id(trait_item.hir_id).to_def_id())
                 );
 
                 if !self.span.filter_generated(trait_item.ident.span) {
                     let span = self.span_from_span(trait_item.ident.span);
-                    let id = id_from_node_id(trait_item.id, &self.save_ctxt);
+                    let id = id_from_hir_id(trait_item.hir_id, &self.save_ctxt);
 
                     self.dumper.dump_def(
                         &Access { public: true, reachable: true },
@@ -1061,13 +1036,16 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                             decl_id: None,
                             docs: self.save_ctxt.docs_for_attrs(&trait_item.attrs),
                             sig: sig::assoc_type_signature(
-                                trait_item.id,
+                                trait_item.hir_id,
                                 trait_item.ident,
                                 Some(bounds),
                                 default_ty.as_ref().map(|ty| &**ty),
                                 &self.save_ctxt,
                             ),
-                            attributes: lower_attributes(trait_item.attrs.clone(), &self.save_ctxt),
+                            attributes: lower_attributes(
+                                trait_item.attrs.to_vec(),
+                                &self.save_ctxt,
+                            ),
                         },
                     );
                 }
@@ -1076,98 +1054,122 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     self.visit_ty(default_ty)
                 }
             }
-            ast::AssocItemKind::MacCall(_) => {}
         }
     }
 
-    fn process_impl_item(&mut self, impl_item: &'l ast::AssocItem, impl_id: DefId) {
+    fn process_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>, impl_id: DefId) {
         self.process_macro_use(impl_item.span);
         match impl_item.kind {
-            ast::AssocItemKind::Const(_, ref ty, ref expr) => {
+            hir::ImplItemKind::Const(ref ty, body) => {
+                let body = self.tcx.hir().body(body);
                 self.process_assoc_const(
-                    impl_item.id,
+                    impl_item.hir_id,
                     impl_item.ident,
                     &ty,
-                    expr.as_deref(),
+                    Some(&body.value),
                     impl_id,
-                    impl_item.vis.clone(),
+                    &impl_item.vis,
                     &impl_item.attrs,
                 );
             }
-            ast::AssocItemKind::Fn(_, ref sig, ref generics, ref body) => {
+            hir::ImplItemKind::Fn(ref sig, body) => {
                 self.process_method(
                     sig,
-                    body.as_deref(),
-                    impl_item.id,
+                    Some(body),
+                    impl_item.hir_id,
                     impl_item.ident,
-                    generics,
-                    impl_item.vis.clone(),
+                    &impl_item.generics,
+                    &impl_item.vis,
                     impl_item.span,
                 );
             }
-            ast::AssocItemKind::TyAlias(_, _, _, None) => {}
-            ast::AssocItemKind::TyAlias(_, _, _, Some(ref ty)) => {
+            hir::ImplItemKind::OpaqueTy(..) => {}
+            hir::ImplItemKind::TyAlias(ref ty) => {
                 // FIXME: uses of the assoc type should ideally point to this
                 // 'def' and the name here should be a ref to the def in the
                 // trait.
                 self.visit_ty(ty)
             }
-            ast::AssocItemKind::MacCall(_) => {}
         }
     }
 
-    /// Dumps imports in a use tree recursively.
-    ///
-    /// A use tree is an import that may contain nested braces (RFC 2128). The `use_tree` parameter
-    /// is the current use tree under scrutiny, while `id` and `prefix` are its corresponding node
-    /// ID and path. `root_item` is the topmost use tree in the hierarchy.
-    ///
-    /// If `use_tree` is a simple or glob import, it is dumped into the analysis data. Otherwise,
-    /// each child use tree is dumped recursively.
-    fn process_use_tree(
-        &mut self,
-        use_tree: &'l ast::UseTree,
-        id: NodeId,
-        root_item: &'l ast::Item,
-        prefix: &ast::Path,
-    ) {
-        let path = &use_tree.prefix;
-
-        // The access is calculated using the current tree ID, but with the root tree's visibility
-        // (since nested trees don't have their own visibility).
-        let hir_id = self.tcx.hir().node_id_to_hir_id(id);
-        let access = access_from!(self.save_ctxt, root_item, hir_id);
-
-        // The parent `DefId` of a given use tree is always the enclosing item.
-        let parent = self
-            .save_ctxt
-            .tcx
-            .hir()
-            .opt_local_def_id_from_node_id(id)
-            .and_then(|id| self.save_ctxt.tcx.parent(id.to_def_id()))
-            .map(id_from_def_id);
-
-        match use_tree.kind {
-            ast::UseTreeKind::Simple(alias, ..) => {
-                let ident = use_tree.ident();
-                let path = ast::Path {
-                    segments: prefix.segments.iter().chain(path.segments.iter()).cloned().collect(),
-                    span: path.span,
-                };
+    pub(crate) fn process_crate(&mut self, krate: &'tcx hir::Crate<'tcx>) {
+        let id = hir::CRATE_HIR_ID;
+        let qualname =
+            format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id(id).to_def_id()));
+
+        let sm = self.tcx.sess.source_map();
+        let filename = sm.span_to_filename(krate.item.span);
+        let data_id = id_from_hir_id(id, &self.save_ctxt);
+        let children = krate
+            .item
+            .module
+            .item_ids
+            .iter()
+            .map(|i| id_from_hir_id(i.id, &self.save_ctxt))
+            .collect();
+        let span = self.span_from_span(krate.item.span);
+
+        self.dumper.dump_def(
+            &Access { public: true, reachable: true },
+            Def {
+                kind: DefKind::Mod,
+                id: data_id,
+                name: String::new(),
+                qualname,
+                span,
+                value: filename.to_string(),
+                children,
+                parent: None,
+                decl_id: None,
+                docs: self.save_ctxt.docs_for_attrs(krate.item.attrs),
+                sig: None,
+                attributes: lower_attributes(krate.item.attrs.to_owned(), &self.save_ctxt),
+            },
+        );
+        intravisit::walk_crate(self, krate);
+    }
+
+    fn process_bounds(&mut self, bounds: hir::GenericBounds<'tcx>) {
+        for bound in bounds {
+            if let hir::GenericBound::Trait(ref trait_ref, _) = *bound {
+                self.process_path(trait_ref.trait_ref.hir_ref_id, &trait_ref.trait_ref.path)
+            }
+        }
+    }
+}
 
+impl<'l, 'tcx> Visitor<'tcx> for DumpVisitor<'l, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+        intravisit::NestedVisitorMap::All(self.tcx.hir())
+    }
+
+    fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
+        self.process_macro_use(item.span);
+        match item.kind {
+            hir::ItemKind::Use(path, hir::UseKind::Single) => {
                 let sub_span = path.segments.last().unwrap().ident.span;
                 if !self.span.filter_generated(sub_span) {
-                    let ref_id = self.lookup_def_id(id).map(id_from_def_id);
-                    let alias_span = alias.map(|i| self.span_from_span(i.span));
+                    let access = access_from!(self.save_ctxt, item, item.hir_id);
+                    let ref_id = self.lookup_def_id(item.hir_id).map(id_from_def_id);
                     let span = self.span_from_span(sub_span);
+                    let parent = self
+                        .save_ctxt
+                        .tcx
+                        .hir()
+                        .opt_local_def_id(item.hir_id)
+                        .and_then(|id| self.save_ctxt.tcx.parent(id.to_def_id()))
+                        .map(id_from_def_id);
                     self.dumper.import(
                         &access,
                         Import {
                             kind: ImportKind::Use,
                             ref_id,
                             span,
-                            alias_span,
-                            name: ident.to_string(),
+                            alias_span: None,
+                            name: item.ident.to_string(),
                             value: String::new(),
                             parent,
                         },
@@ -1175,25 +1177,27 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     self.write_sub_paths_truncated(&path);
                 }
             }
-            ast::UseTreeKind::Glob => {
-                let path = ast::Path {
-                    segments: prefix.segments.iter().chain(path.segments.iter()).cloned().collect(),
-                    span: path.span,
-                };
-
+            hir::ItemKind::Use(path, hir::UseKind::Glob) => {
                 // Make a comma-separated list of names of imported modules.
-                let def_id = self.tcx.hir().local_def_id_from_node_id(id);
+                let def_id = self.tcx.hir().local_def_id(item.hir_id);
                 let names = self.tcx.names_imported_by_glob_use(def_id);
                 let names: Vec<_> = names.iter().map(|n| n.to_string()).collect();
 
                 // Otherwise it's a span with wrong macro expansion info, which
                 // we don't want to track anyway, since it's probably macro-internal `use`
                 if let Some(sub_span) =
-                    self.span.sub_span_of_token(use_tree.span, token::BinOp(token::Star))
+                    self.span.sub_span_of_token(item.span, token::BinOp(token::Star))
                 {
-                    if !self.span.filter_generated(use_tree.span) {
+                    if !self.span.filter_generated(item.span) {
+                        let access = access_from!(self.save_ctxt, item, item.hir_id);
                         let span = self.span_from_span(sub_span);
-
+                        let parent = self
+                            .save_ctxt
+                            .tcx
+                            .hir()
+                            .opt_local_def_id(item.hir_id)
+                            .and_then(|id| self.save_ctxt.tcx.parent(id.to_def_id()))
+                            .map(id_from_def_id);
                         self.dumper.import(
                             &access,
                             Import {
@@ -1210,73 +1214,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     }
                 }
             }
-            ast::UseTreeKind::Nested(ref nested_items) => {
-                let prefix = ast::Path {
-                    segments: prefix.segments.iter().chain(path.segments.iter()).cloned().collect(),
-                    span: path.span,
-                };
-                for &(ref tree, id) in nested_items {
-                    self.process_use_tree(tree, id, root_item, &prefix);
-                }
-            }
-        }
-    }
-
-    fn process_bounds(&mut self, bounds: &'l ast::GenericBounds) {
-        for bound in bounds {
-            if let ast::GenericBound::Trait(ref trait_ref, _) = *bound {
-                self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path)
-            }
-        }
-    }
-}
-
-impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
-    fn visit_mod(&mut self, m: &'l ast::Mod, span: Span, attrs: &[ast::Attribute], id: NodeId) {
-        // Since we handle explicit modules ourselves in visit_item, this should
-        // only get called for the root module of a crate.
-        assert_eq!(id, ast::CRATE_NODE_ID);
-
-        let qualname = format!(
-            "::{}",
-            self.tcx.def_path_str(self.tcx.hir().local_def_id_from_node_id(id).to_def_id())
-        );
-
-        let sm = self.tcx.sess.source_map();
-        let filename = sm.span_to_filename(span);
-        let data_id = id_from_node_id(id, &self.save_ctxt);
-        let children = m.items.iter().map(|i| id_from_node_id(i.id, &self.save_ctxt)).collect();
-        let span = self.span_from_span(span);
-
-        self.dumper.dump_def(
-            &Access { public: true, reachable: true },
-            Def {
-                kind: DefKind::Mod,
-                id: data_id,
-                name: String::new(),
-                qualname,
-                span,
-                value: filename.to_string(),
-                children,
-                parent: None,
-                decl_id: None,
-                docs: self.save_ctxt.docs_for_attrs(attrs),
-                sig: None,
-                attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt),
-            },
-        );
-        visit::walk_mod(self, m);
-    }
-
-    fn visit_item(&mut self, item: &'l ast::Item) {
-        use rustc_ast::ast::ItemKind::*;
-        self.process_macro_use(item.span);
-        match item.kind {
-            Use(ref use_tree) => {
-                let prefix = ast::Path { segments: vec![], span: DUMMY_SP };
-                self.process_use_tree(use_tree, item.id, item, &prefix);
-            }
-            ExternCrate(_) => {
+            hir::ItemKind::ExternCrate(_) => {
                 let name_span = item.ident.span;
                 if !self.span.filter_generated(name_span) {
                     let span = self.span_from_span(name_span);
@@ -1284,7 +1222,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
                         .save_ctxt
                         .tcx
                         .hir()
-                        .opt_local_def_id_from_node_id(item.id)
+                        .opt_local_def_id(item.hir_id)
                         .and_then(|id| self.save_ctxt.tcx.parent(id.to_def_id()))
                         .map(id_from_def_id);
                     self.dumper.import(
@@ -1301,43 +1239,44 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
                     );
                 }
             }
-            Fn(_, ref sig, ref ty_params, ref body) => {
-                self.process_fn(item, &sig.decl, &sig.header, ty_params, body.as_deref())
+            hir::ItemKind::Fn(ref sig, ref ty_params, body) => {
+                self.process_fn(item, sig.decl, &sig.header, ty_params, body)
+            }
+            hir::ItemKind::Static(ref typ, _, body) => {
+                let body = self.tcx.hir().body(body);
+                self.process_static_or_const_item(item, typ, &body.value)
+            }
+            hir::ItemKind::Const(ref typ, body) => {
+                let body = self.tcx.hir().body(body);
+                self.process_static_or_const_item(item, typ, &body.value)
             }
-            Static(ref typ, _, ref e) => self.process_static_or_const_item(item, typ, e.as_deref()),
-            Const(_, ref typ, ref e) => self.process_static_or_const_item(item, typ, e.as_deref()),
-            Struct(ref def, ref ty_params) | Union(ref def, ref ty_params) => {
+            hir::ItemKind::Struct(ref def, ref ty_params)
+            | hir::ItemKind::Union(ref def, ref ty_params) => {
                 self.process_struct(item, def, ty_params)
             }
-            Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
-            Impl { ref generics, ref of_trait, ref self_ty, ref items, .. } => {
+            hir::ItemKind::Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
+            hir::ItemKind::Impl { ref generics, ref of_trait, ref self_ty, ref items, .. } => {
                 self.process_impl(item, generics, of_trait, &self_ty, items)
             }
-            Trait(_, _, ref generics, ref trait_refs, ref methods) => {
+            hir::ItemKind::Trait(_, _, ref generics, ref trait_refs, methods) => {
                 self.process_trait(item, generics, trait_refs, methods)
             }
-            Mod(ref m) => {
+            hir::ItemKind::Mod(ref m) => {
                 self.process_mod(item);
-                visit::walk_mod(self, m);
+                intravisit::walk_mod(self, m, item.hir_id);
             }
-            TyAlias(_, ref ty_params, _, ref ty) => {
+            hir::ItemKind::TyAlias(ty, ref generics) => {
                 let qualname = format!(
                     "::{}",
-                    self.tcx.def_path_str(
-                        self.tcx.hir().local_def_id_from_node_id(item.id).to_def_id()
-                    )
+                    self.tcx.def_path_str(self.tcx.hir().local_def_id(item.hir_id).to_def_id())
                 );
-                let value = match ty {
-                    Some(ty) => ty_to_string(&ty),
-                    None => "_".to_string(),
-                };
+                let value = ty_to_string(&ty);
                 if !self.span.filter_generated(item.ident.span) {
                     let span = self.span_from_span(item.ident.span);
-                    let id = id_from_node_id(item.id, &self.save_ctxt);
-                    let hir_id = self.tcx.hir().node_id_to_hir_id(item.id);
+                    let id = id_from_hir_id(item.hir_id, &self.save_ctxt);
 
                     self.dumper.dump_def(
-                        &access_from!(self.save_ctxt, item, hir_id),
+                        &access_from!(self.save_ctxt, item, item.hir_id),
                         Def {
                             kind: DefKind::Type,
                             id,
@@ -1350,52 +1289,51 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
                             decl_id: None,
                             docs: self.save_ctxt.docs_for_attrs(&item.attrs),
                             sig: sig::item_signature(item, &self.save_ctxt),
-                            attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
+                            attributes: lower_attributes(item.attrs.to_vec(), &self.save_ctxt),
                         },
                     );
                 }
 
-                walk_list!(self, visit_ty, ty);
-                self.process_generic_params(ty_params, &qualname, item.id);
+                self.visit_ty(ty);
+                self.process_generic_params(generics, &qualname, item.hir_id);
             }
-            MacCall(_) => (),
-            _ => visit::walk_item(self, item),
+            _ => intravisit::walk_item(self, item),
         }
     }
 
-    fn visit_generics(&mut self, generics: &'l ast::Generics) {
-        for param in &generics.params {
+    fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
+        for param in generics.params {
             match param.kind {
-                ast::GenericParamKind::Lifetime { .. } => {}
-                ast::GenericParamKind::Type { ref default, .. } => {
-                    self.process_bounds(&param.bounds);
+                hir::GenericParamKind::Lifetime { .. } => {}
+                hir::GenericParamKind::Type { ref default, .. } => {
+                    self.process_bounds(param.bounds);
                     if let Some(ref ty) = default {
-                        self.visit_ty(&ty);
+                        self.visit_ty(ty);
                     }
                 }
-                ast::GenericParamKind::Const { ref ty } => {
-                    self.process_bounds(&param.bounds);
-                    self.visit_ty(&ty);
+                hir::GenericParamKind::Const { ref ty } => {
+                    self.process_bounds(param.bounds);
+                    self.visit_ty(ty);
                 }
             }
         }
-        for pred in &generics.where_clause.predicates {
-            if let ast::WherePredicate::BoundPredicate(ref wbp) = *pred {
-                self.process_bounds(&wbp.bounds);
-                self.visit_ty(&wbp.bounded_ty);
+        for pred in generics.where_clause.predicates {
+            if let hir::WherePredicate::BoundPredicate(ref wbp) = *pred {
+                self.process_bounds(wbp.bounds);
+                self.visit_ty(wbp.bounded_ty);
             }
         }
     }
 
-    fn visit_ty(&mut self, t: &'l ast::Ty) {
+    fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
         self.process_macro_use(t.span);
         match t.kind {
-            ast::TyKind::Path(_, ref path) => {
+            hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
                 if generated_code(t.span) {
                     return;
                 }
 
-                if let Some(id) = self.lookup_def_id(t.id) {
+                if let Some(id) = self.lookup_def_id(t.hir_id) {
                     let sub_span = path.segments.last().unwrap().ident.span;
                     let span = self.span_from_span(sub_span);
                     self.dumper.dump_ref(Ref {
@@ -1406,57 +1344,37 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
                 }
 
                 self.write_sub_paths_truncated(path);
-                visit::walk_path(self, path);
+                intravisit::walk_path(self, path);
             }
-            ast::TyKind::Array(ref element, ref length) => {
-                self.visit_ty(element);
-                let hir_id = self.tcx.hir().node_id_to_hir_id(length.id);
-                self.nest_tables(self.tcx.hir().local_def_id(hir_id), |v| {
-                    v.visit_expr(&length.value)
+            hir::TyKind::Array(ref ty, ref anon_const) => {
+                self.visit_ty(ty);
+                let map = self.tcx.hir();
+                self.nest_tables(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+                    v.visit_expr(&map.body(anon_const.body).value)
                 });
             }
-            ast::TyKind::ImplTrait(id, ref bounds) => {
-                // FIXME: As of writing, the opaque type lowering introduces
-                // another DefPath scope/segment (used to declare the resulting
-                // opaque type item).
-                // However, the synthetic scope does *not* have associated
-                // typeck tables, which means we can't nest it and we fire an
-                // assertion when resolving the qualified type paths in trait
-                // bounds...
-                // This will panic if called on return type `impl Trait`, which
-                // we guard against in `process_fn`.
-                // FIXME(#71104) Should really be using just `node_id_to_hir_id` but
-                // some `NodeId` do not seem to have a corresponding HirId.
-                if let Some(hir_id) = self.tcx.hir().opt_node_id_to_hir_id(id) {
-                    self.nest_tables(self.tcx.hir().local_def_id(hir_id), |v| {
-                        v.process_bounds(bounds)
-                    });
-                }
-            }
-            _ => visit::walk_ty(self, t),
+            _ => intravisit::walk_ty(self, t),
         }
     }
 
-    fn visit_expr(&mut self, ex: &'l ast::Expr) {
+    fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
         debug!("visit_expr {:?}", ex.kind);
         self.process_macro_use(ex.span);
         match ex.kind {
-            ast::ExprKind::Struct(ref path, ref fields, ref base) => {
-                let expr_hir_id = self.save_ctxt.tcx.hir().node_id_to_hir_id(ex.id);
-                let hir_expr = self.save_ctxt.tcx.hir().expect_expr(expr_hir_id);
+            hir::ExprKind::Struct(ref path, ref fields, ref base) => {
+                let hir_expr = self.save_ctxt.tcx.hir().expect_expr(ex.hir_id);
                 let adt = match self.save_ctxt.tables.expr_ty_opt(&hir_expr) {
                     Some(ty) if ty.ty_adt_def().is_some() => ty.ty_adt_def().unwrap(),
                     _ => {
-                        visit::walk_expr(self, ex);
+                        intravisit::walk_expr(self, ex);
                         return;
                     }
                 };
-                let node_id = self.save_ctxt.tcx.hir().hir_id_to_node_id(hir_expr.hir_id);
-                let res = self.save_ctxt.get_path_res(node_id);
-                self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), base)
+                let res = self.save_ctxt.get_path_res(hir_expr.hir_id);
+                self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), *base)
             }
-            ast::ExprKind::MethodCall(ref seg, ref args) => self.process_method_call(ex, seg, args),
-            ast::ExprKind::Field(ref sub_ex, _) => {
+            hir::ExprKind::MethodCall(ref seg, _, args) => self.process_method_call(ex, seg, args),
+            hir::ExprKind::Field(ref sub_ex, _) => {
                 self.visit_expr(&sub_ex);
 
                 if let Some(field_data) = self.save_ctxt.get_expr_data(ex) {
@@ -1466,71 +1384,62 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
                     }
                 }
             }
-            ast::ExprKind::Closure(_, _, _, ref decl, ref body, _fn_decl_span) => {
-                let id = format!("${}", ex.id);
+            hir::ExprKind::Closure(_, ref decl, body, _fn_decl_span, _) => {
+                let id = format!("${}", ex.hir_id);
 
                 // walk arg and return types
-                for arg in &decl.inputs {
-                    self.visit_ty(&arg.ty);
+                for ty in decl.inputs {
+                    self.visit_ty(ty);
                 }
 
-                if let ast::FnRetTy::Ty(ref ret_ty) = decl.output {
-                    self.visit_ty(&ret_ty);
+                if let hir::FnRetTy::Return(ref ret_ty) = decl.output {
+                    self.visit_ty(ret_ty);
                 }
 
                 // walk the body
-                let hir_id = self.tcx.hir().node_id_to_hir_id(ex.id);
-                self.nest_tables(self.tcx.hir().local_def_id(hir_id), |v| {
-                    v.process_formals(&decl.inputs, &id);
-                    v.visit_expr(body)
+                let map = self.tcx.hir();
+                self.nest_tables(self.tcx.hir().local_def_id(ex.hir_id), |v| {
+                    let body = map.body(body);
+                    v.process_formals(body.params, &id);
+                    v.visit_expr(&body.value)
                 });
             }
-            ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) => {
-                self.process_var_decl(pattern);
-                debug!("for loop, walk sub-expr: {:?}", subexpression.kind);
-                self.visit_expr(subexpression);
-                visit::walk_block(self, block);
-            }
-            ast::ExprKind::Let(ref pat, ref scrutinee) => {
-                self.process_var_decl(pat);
-                self.visit_expr(scrutinee);
-            }
-            ast::ExprKind::Repeat(ref element, ref count) => {
-                self.visit_expr(element);
-                let hir_id = self.tcx.hir().node_id_to_hir_id(count.id);
-                self.nest_tables(self.tcx.hir().local_def_id(hir_id), |v| {
-                    v.visit_expr(&count.value)
+            hir::ExprKind::Repeat(ref expr, ref anon_const) => {
+                self.visit_expr(expr);
+                let map = self.tcx.hir();
+                self.nest_tables(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+                    v.visit_expr(&map.body(anon_const.body).value)
                 });
             }
             // In particular, we take this branch for call and path expressions,
             // where we'll index the idents involved just by continuing to walk.
-            _ => visit::walk_expr(self, ex),
+            _ => intravisit::walk_expr(self, ex),
         }
     }
 
-    fn visit_pat(&mut self, p: &'l ast::Pat) {
+    fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
         self.process_macro_use(p.span);
         self.process_pat(p);
     }
 
-    fn visit_arm(&mut self, arm: &'l ast::Arm) {
+    fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
         self.process_var_decl(&arm.pat);
-        if let Some(expr) = &arm.guard {
+        if let Some(hir::Guard::If(expr)) = &arm.guard {
             self.visit_expr(expr);
         }
         self.visit_expr(&arm.body);
     }
 
-    fn visit_path(&mut self, p: &'l ast::Path, id: NodeId) {
+    fn visit_path(&mut self, p: &'tcx hir::Path<'tcx>, id: hir::HirId) {
         self.process_path(id, p);
     }
 
-    fn visit_stmt(&mut self, s: &'l ast::Stmt) {
+    fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
         self.process_macro_use(s.span);
-        visit::walk_stmt(self, s)
+        intravisit::walk_stmt(self, s)
     }
 
-    fn visit_local(&mut self, l: &'l ast::Local) {
+    fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
         self.process_macro_use(l.span);
         self.process_var_decl(&l.pat);
 
@@ -1539,29 +1448,27 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
         walk_list!(self, visit_expr, &l.init);
     }
 
-    fn visit_foreign_item(&mut self, item: &'l ast::ForeignItem) {
-        let hir_id = self.tcx.hir().node_id_to_hir_id(item.id);
-        let access = access_from!(self.save_ctxt, item, hir_id);
+    fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
+        let access = access_from!(self.save_ctxt, item, item.hir_id);
 
         match item.kind {
-            ast::ForeignItemKind::Fn(_, ref sig, ref generics, _) => {
-                let decl = &sig.decl;
+            hir::ForeignItemKind::Fn(decl, _, ref generics) => {
                 if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) {
                     down_cast_data!(fn_data, DefData, item.span);
 
-                    self.process_generic_params(generics, &fn_data.qualname, item.id);
+                    self.process_generic_params(generics, &fn_data.qualname, item.hir_id);
                     self.dumper.dump_def(&access, fn_data);
                 }
 
-                for arg in &decl.inputs {
-                    self.visit_ty(&arg.ty);
+                for ty in decl.inputs {
+                    self.visit_ty(ty);
                 }
 
-                if let ast::FnRetTy::Ty(ref ret_ty) = decl.output {
-                    self.visit_ty(&ret_ty);
+                if let hir::FnRetTy::Return(ref ret_ty) = decl.output {
+                    self.visit_ty(ret_ty);
                 }
             }
-            ast::ForeignItemKind::Static(ref ty, _, _) => {
+            hir::ForeignItemKind::Static(ref ty, _) => {
                 if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
                     down_cast_data!(var_data, DefData, item.span);
                     self.dumper.dump_def(&access, var_data);
@@ -1569,13 +1476,12 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
 
                 self.visit_ty(ty);
             }
-            ast::ForeignItemKind::TyAlias(..) => {
+            hir::ForeignItemKind::Type => {
                 if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
                     down_cast_data!(var_data, DefData, item.span);
                     self.dumper.dump_def(&access, var_data);
                 }
             }
-            ast::ForeignItemKind::MacCall(..) => {}
         }
     }
 }
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 3bd68a9c656..8c7731c18e9 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -9,14 +9,16 @@ mod dumper;
 mod span_utils;
 mod sig;
 
-use rustc_ast::ast::{self, Attribute, NodeId, PatKind, DUMMY_NODE_ID};
+use rustc_ast::ast::{self};
 use rustc_ast::util::comments::strip_doc_comment_decoration;
-use rustc_ast::visit::{self, Visitor};
-use rustc_ast_pretty::pprust::{self, param_to_string, ty_to_string};
+use rustc_ast_pretty::pprust::attribute_to_string;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind as HirDefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::Node;
+use rustc_hir_pretty::ty_to_string;
+use rustc_middle::hir::map::Map;
 use rustc_middle::middle::cstore::ExternCrate;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::{self, DefIdTree, TyCtxt};
@@ -129,34 +131,32 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
         result
     }
 
-    pub fn get_extern_item_data(&self, item: &ast::ForeignItem) -> Option<Data> {
-        let qualname = format!(
-            "::{}",
-            self.tcx.def_path_str(self.tcx.hir().local_def_id_from_node_id(item.id).to_def_id())
-        );
+    pub fn get_extern_item_data(&self, item: &hir::ForeignItem<'_>) -> Option<Data> {
+        let def_id = self.tcx.hir().local_def_id(item.hir_id).to_def_id();
+        let qualname = format!("::{}", self.tcx.def_path_str(def_id));
         match item.kind {
-            ast::ForeignItemKind::Fn(_, ref sig, ref generics, _) => {
+            hir::ForeignItemKind::Fn(ref decl, _, ref generics) => {
                 filter!(self.span_utils, item.ident.span);
 
                 Some(Data::DefData(Def {
                     kind: DefKind::ForeignFunction,
-                    id: id_from_node_id(item.id, self),
+                    id: id_from_def_id(def_id),
                     span: self.span_from_span(item.ident.span),
                     name: item.ident.to_string(),
                     qualname,
-                    value: make_signature(&sig.decl, generics),
+                    value: make_signature(decl, generics),
                     parent: None,
                     children: vec![],
                     decl_id: None,
                     docs: self.docs_for_attrs(&item.attrs),
                     sig: sig::foreign_item_signature(item, self),
-                    attributes: lower_attributes(item.attrs.clone(), self),
+                    attributes: lower_attributes(item.attrs.to_vec(), self),
                 }))
             }
-            ast::ForeignItemKind::Static(ref ty, _, _) => {
+            hir::ForeignItemKind::Static(ref ty, _) => {
                 filter!(self.span_utils, item.ident.span);
 
-                let id = id_from_node_id(item.id, self);
+                let id = id_from_def_id(def_id);
                 let span = self.span_from_span(item.ident.span);
 
                 Some(Data::DefData(Def {
@@ -171,28 +171,23 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
                     decl_id: None,
                     docs: self.docs_for_attrs(&item.attrs),
                     sig: sig::foreign_item_signature(item, self),
-                    attributes: lower_attributes(item.attrs.clone(), self),
+                    attributes: lower_attributes(item.attrs.to_vec(), self),
                 }))
             }
             // FIXME(plietar): needs a new DefKind in rls-data
-            ast::ForeignItemKind::TyAlias(..) => None,
-            ast::ForeignItemKind::MacCall(..) => None,
+            hir::ForeignItemKind::Type => None,
         }
     }
 
-    pub fn get_item_data(&self, item: &ast::Item) -> Option<Data> {
+    pub fn get_item_data(&self, item: &hir::Item<'_>) -> Option<Data> {
+        let def_id = self.tcx.hir().local_def_id(item.hir_id).to_def_id();
         match item.kind {
-            ast::ItemKind::Fn(_, ref sig, .., ref generics, _) => {
-                let qualname = format!(
-                    "::{}",
-                    self.tcx.def_path_str(
-                        self.tcx.hir().local_def_id_from_node_id(item.id).to_def_id()
-                    )
-                );
+            hir::ItemKind::Fn(ref sig, ref generics, _) => {
+                let qualname = format!("::{}", self.tcx.def_path_str(def_id));
                 filter!(self.span_utils, item.ident.span);
                 Some(Data::DefData(Def {
                     kind: DefKind::Function,
-                    id: id_from_node_id(item.id, self),
+                    id: id_from_def_id(def_id),
                     span: self.span_from_span(item.ident.span),
                     name: item.ident.to_string(),
                     qualname,
@@ -202,20 +197,15 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
                     decl_id: None,
                     docs: self.docs_for_attrs(&item.attrs),
                     sig: sig::item_signature(item, self),
-                    attributes: lower_attributes(item.attrs.clone(), self),
+                    attributes: lower_attributes(item.attrs.to_vec(), self),
                 }))
             }
-            ast::ItemKind::Static(ref typ, ..) => {
-                let qualname = format!(
-                    "::{}",
-                    self.tcx.def_path_str(
-                        self.tcx.hir().local_def_id_from_node_id(item.id).to_def_id()
-                    )
-                );
+            hir::ItemKind::Static(ref typ, ..) => {
+                let qualname = format!("::{}", self.tcx.def_path_str(def_id));
 
                 filter!(self.span_utils, item.ident.span);
 
-                let id = id_from_node_id(item.id, self);
+                let id = id_from_def_id(def_id);
                 let span = self.span_from_span(item.ident.span);
 
                 Some(Data::DefData(Def {
@@ -230,19 +220,14 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
                     decl_id: None,
                     docs: self.docs_for_attrs(&item.attrs),
                     sig: sig::item_signature(item, self),
-                    attributes: lower_attributes(item.attrs.clone(), self),
+                    attributes: lower_attributes(item.attrs.to_vec(), self),
                 }))
             }
-            ast::ItemKind::Const(_, ref typ, _) => {
-                let qualname = format!(
-                    "::{}",
-                    self.tcx.def_path_str(
-                        self.tcx.hir().local_def_id_from_node_id(item.id).to_def_id()
-                    )
-                );
+            hir::ItemKind::Const(ref typ, _) => {
+                let qualname = format!("::{}", self.tcx.def_path_str(def_id));
                 filter!(self.span_utils, item.ident.span);
 
-                let id = id_from_node_id(item.id, self);
+                let id = id_from_def_id(def_id);
                 let span = self.span_from_span(item.ident.span);
 
                 Some(Data::DefData(Def {
@@ -257,16 +242,11 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
                     decl_id: None,
                     docs: self.docs_for_attrs(&item.attrs),
                     sig: sig::item_signature(item, self),
-                    attributes: lower_attributes(item.attrs.clone(), self),
+                    attributes: lower_attributes(item.attrs.to_vec(), self),
                 }))
             }
-            ast::ItemKind::Mod(ref m) => {
-                let qualname = format!(
-                    "::{}",
-                    self.tcx.def_path_str(
-                        self.tcx.hir().local_def_id_from_node_id(item.id).to_def_id()
-                    )
-                );
+            hir::ItemKind::Mod(ref m) => {
+                let qualname = format!("::{}", self.tcx.def_path_str(def_id));
 
                 let sm = self.tcx.sess.source_map();
                 let filename = sm.span_to_filename(m.inner);
@@ -275,48 +255,43 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
 
                 Some(Data::DefData(Def {
                     kind: DefKind::Mod,
-                    id: id_from_node_id(item.id, self),
+                    id: id_from_def_id(def_id),
                     name: item.ident.to_string(),
                     qualname,
                     span: self.span_from_span(item.ident.span),
                     value: filename.to_string(),
                     parent: None,
-                    children: m.items.iter().map(|i| id_from_node_id(i.id, self)).collect(),
+                    children: m.item_ids.iter().map(|i| id_from_hir_id(i.id, self)).collect(),
                     decl_id: None,
                     docs: self.docs_for_attrs(&item.attrs),
                     sig: sig::item_signature(item, self),
-                    attributes: lower_attributes(item.attrs.clone(), self),
+                    attributes: lower_attributes(item.attrs.to_vec(), self),
                 }))
             }
-            ast::ItemKind::Enum(ref def, _) => {
+            hir::ItemKind::Enum(ref def, _) => {
                 let name = item.ident.to_string();
-                let qualname = format!(
-                    "::{}",
-                    self.tcx.def_path_str(
-                        self.tcx.hir().local_def_id_from_node_id(item.id).to_def_id()
-                    )
-                );
+                let qualname = format!("::{}", self.tcx.def_path_str(def_id));
                 filter!(self.span_utils, item.ident.span);
                 let variants_str =
                     def.variants.iter().map(|v| v.ident.to_string()).collect::<Vec<_>>().join(", ");
                 let value = format!("{}::{{{}}}", name, variants_str);
                 Some(Data::DefData(Def {
                     kind: DefKind::Enum,
-                    id: id_from_node_id(item.id, self),
+                    id: id_from_def_id(def_id),
                     span: self.span_from_span(item.ident.span),
                     name,
                     qualname,
                     value,
                     parent: None,
-                    children: def.variants.iter().map(|v| id_from_node_id(v.id, self)).collect(),
+                    children: def.variants.iter().map(|v| id_from_hir_id(v.id, self)).collect(),
                     decl_id: None,
                     docs: self.docs_for_attrs(&item.attrs),
                     sig: sig::item_signature(item, self),
-                    attributes: lower_attributes(item.attrs.clone(), self),
+                    attributes: lower_attributes(item.attrs.to_vec(), self),
                 }))
             }
-            ast::ItemKind::Impl { ref of_trait, ref self_ty, ref items, .. } => {
-                if let ast::TyKind::Path(None, ref path) = self_ty.kind {
+            hir::ItemKind::Impl { ref of_trait, ref self_ty, ref items, .. } => {
+                if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = self_ty.kind {
                     // Common case impl for a struct or something basic.
                     if generated_code(path.span) {
                         return None;
@@ -327,7 +302,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
                     let impl_id = self.next_impl_id();
                     let span = self.span_from_span(sub_span);
 
-                    let type_data = self.lookup_def_id(self_ty.id);
+                    let type_data = self.lookup_def_id(self_ty.hir_id);
                     type_data.map(|type_data| {
                         Data::RelationData(
                             Relation {
@@ -336,7 +311,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
                                 from: id_from_def_id(type_data),
                                 to: of_trait
                                     .as_ref()
-                                    .and_then(|t| self.lookup_def_id(t.ref_id))
+                                    .and_then(|t| self.lookup_def_id(t.hir_ref_id))
                                     .map(id_from_def_id)
                                     .unwrap_or_else(null_id),
                             },
@@ -351,7 +326,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
                                 parent: None,
                                 children: items
                                     .iter()
-                                    .map(|i| id_from_node_id(i.id, self))
+                                    .map(|i| id_from_hir_id(i.id.hir_id, self))
                                     .collect(),
                                 docs: String::new(),
                                 sig: None,
@@ -370,126 +345,120 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
         }
     }
 
-    pub fn get_field_data(&self, field: &ast::StructField, scope: NodeId) -> Option<Def> {
-        if let Some(ident) = field.ident {
-            let name = ident.to_string();
-            let qualname = format!(
-                "::{}::{}",
-                self.tcx.def_path_str(self.tcx.hir().local_def_id_from_node_id(scope).to_def_id()),
-                ident
-            );
-            filter!(self.span_utils, ident.span);
-            let def_id = self.tcx.hir().local_def_id_from_node_id(field.id).to_def_id();
-            let typ = self.tcx.type_of(def_id).to_string();
-
-            let id = id_from_node_id(field.id, self);
-            let span = self.span_from_span(ident.span);
-
-            Some(Def {
-                kind: DefKind::Field,
-                id,
-                span,
-                name,
-                qualname,
-                value: typ,
-                parent: Some(id_from_node_id(scope, self)),
-                children: vec![],
-                decl_id: None,
-                docs: self.docs_for_attrs(&field.attrs),
-                sig: sig::field_signature(field, self),
-                attributes: lower_attributes(field.attrs.clone(), self),
-            })
-        } else {
-            None
-        }
+    pub fn get_field_data(&self, field: &hir::StructField<'_>, scope: hir::HirId) -> Option<Def> {
+        let name = field.ident.to_string();
+        let scope_def_id = self.tcx.hir().local_def_id(scope).to_def_id();
+        let qualname = format!("::{}::{}", self.tcx.def_path_str(scope_def_id), field.ident);
+        filter!(self.span_utils, field.ident.span);
+        let field_def_id = self.tcx.hir().local_def_id(field.hir_id).to_def_id();
+        let typ = self.tcx.type_of(field_def_id).to_string();
+
+        let id = id_from_def_id(field_def_id);
+        let span = self.span_from_span(field.ident.span);
+
+        Some(Def {
+            kind: DefKind::Field,
+            id,
+            span,
+            name,
+            qualname,
+            value: typ,
+            parent: Some(id_from_def_id(scope_def_id)),
+            children: vec![],
+            decl_id: None,
+            docs: self.docs_for_attrs(&field.attrs),
+            sig: sig::field_signature(field, self),
+            attributes: lower_attributes(field.attrs.to_vec(), self),
+        })
     }
 
     // FIXME would be nice to take a MethodItem here, but the ast provides both
     // trait and impl flavours, so the caller must do the disassembly.
-    pub fn get_method_data(&self, id: ast::NodeId, ident: Ident, span: Span) -> Option<Def> {
+    pub fn get_method_data(&self, hir_id: hir::HirId, ident: Ident, span: Span) -> Option<Def> {
         // The qualname for a method is the trait name or name of the struct in an impl in
         // which the method is declared in, followed by the method's name.
-        let (qualname, parent_scope, decl_id, docs, attributes) = match self
-            .tcx
-            .impl_of_method(self.tcx.hir().local_def_id_from_node_id(id).to_def_id())
-        {
-            Some(impl_id) => match self.tcx.hir().get_if_local(impl_id) {
-                Some(Node::Item(item)) => match item.kind {
-                    hir::ItemKind::Impl { ref self_ty, .. } => {
-                        let hir = self.tcx.hir();
-
-                        let mut qualname = String::from("<");
-                        qualname.push_str(&rustc_hir_pretty::id_to_string(&hir, self_ty.hir_id));
-
-                        let trait_id = self.tcx.trait_id_of_impl(impl_id);
+        let def_id = self.tcx.hir().local_def_id(hir_id).to_def_id();
+        let (qualname, parent_scope, decl_id, docs, attributes) =
+            match self.tcx.impl_of_method(def_id) {
+                Some(impl_id) => match self.tcx.hir().get_if_local(impl_id) {
+                    Some(Node::Item(item)) => match item.kind {
+                        hir::ItemKind::Impl { ref self_ty, .. } => {
+                            let hir = self.tcx.hir();
+
+                            let mut qualname = String::from("<");
+                            qualname
+                                .push_str(&rustc_hir_pretty::id_to_string(&hir, self_ty.hir_id));
+
+                            let trait_id = self.tcx.trait_id_of_impl(impl_id);
+                            let mut docs = String::new();
+                            let mut attrs = vec![];
+                            if let Some(Node::ImplItem(item)) = hir.find(hir_id) {
+                                docs = self.docs_for_attrs(&item.attrs);
+                                attrs = item.attrs.to_vec();
+                            }
+
+                            let mut decl_id = None;
+                            if let Some(def_id) = trait_id {
+                                // A method in a trait impl.
+                                qualname.push_str(" as ");
+                                qualname.push_str(&self.tcx.def_path_str(def_id));
+
+                                decl_id = self
+                                    .tcx
+                                    .associated_items(def_id)
+                                    .filter_by_name_unhygienic(ident.name)
+                                    .next()
+                                    .map(|item| item.def_id);
+                            }
+                            qualname.push_str(">");
+
+                            (qualname, trait_id, decl_id, docs, attrs)
+                        }
+                        _ => {
+                            span_bug!(
+                                span,
+                                "Container {:?} for method {} not an impl?",
+                                impl_id,
+                                hir_id
+                            );
+                        }
+                    },
+                    r => {
+                        span_bug!(
+                            span,
+                            "Container {:?} for method {} is not a node item {:?}",
+                            impl_id,
+                            hir_id,
+                            r
+                        );
+                    }
+                },
+                None => match self.tcx.trait_of_item(def_id) {
+                    Some(def_id) => {
                         let mut docs = String::new();
                         let mut attrs = vec![];
-                        if let Some(Node::ImplItem(item)) = hir.find(hir.node_id_to_hir_id(id)) {
+
+                        if let Some(Node::TraitItem(item)) = self.tcx.hir().find(hir_id) {
                             docs = self.docs_for_attrs(&item.attrs);
                             attrs = item.attrs.to_vec();
                         }
 
-                        let mut decl_id = None;
-                        if let Some(def_id) = trait_id {
-                            // A method in a trait impl.
-                            qualname.push_str(" as ");
-                            qualname.push_str(&self.tcx.def_path_str(def_id));
-
-                            decl_id = self
-                                .tcx
-                                .associated_items(def_id)
-                                .filter_by_name_unhygienic(ident.name)
-                                .next()
-                                .map(|item| item.def_id);
-                        }
-                        qualname.push_str(">");
-
-                        (qualname, trait_id, decl_id, docs, attrs)
+                        (
+                            format!("::{}", self.tcx.def_path_str(def_id)),
+                            Some(def_id),
+                            None,
+                            docs,
+                            attrs,
+                        )
                     }
-                    _ => {
-                        span_bug!(span, "Container {:?} for method {} not an impl?", impl_id, id);
+                    None => {
+                        debug!("could not find container for method {} at {:?}", hir_id, span);
+                        // This is not necessarily a bug, if there was a compilation error,
+                        // the tables we need might not exist.
+                        return None;
                     }
                 },
-                r => {
-                    span_bug!(
-                        span,
-                        "Container {:?} for method {} is not a node item {:?}",
-                        impl_id,
-                        id,
-                        r
-                    );
-                }
-            },
-            None => match self
-                .tcx
-                .trait_of_item(self.tcx.hir().local_def_id_from_node_id(id).to_def_id())
-            {
-                Some(def_id) => {
-                    let mut docs = String::new();
-                    let mut attrs = vec![];
-                    let hir_id = self.tcx.hir().node_id_to_hir_id(id);
-
-                    if let Some(Node::TraitItem(item)) = self.tcx.hir().find(hir_id) {
-                        docs = self.docs_for_attrs(&item.attrs);
-                        attrs = item.attrs.to_vec();
-                    }
-
-                    (
-                        format!("::{}", self.tcx.def_path_str(def_id)),
-                        Some(def_id),
-                        None,
-                        docs,
-                        attrs,
-                    )
-                }
-                None => {
-                    debug!("could not find container for method {} at {:?}", id, span);
-                    // This is not necessarily a bug, if there was a compilation error,
-                    // the tables we need might not exist.
-                    return None;
-                }
-            },
-        };
+            };
 
         let qualname = format!("{}::{}", qualname, ident.name);
 
@@ -497,7 +466,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
 
         Some(Def {
             kind: DefKind::Method,
-            id: id_from_node_id(id, self),
+            id: id_from_def_id(def_id),
             span: self.span_from_span(ident.span),
             name: ident.name.to_string(),
             qualname,
@@ -512,8 +481,8 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
         })
     }
 
-    pub fn get_trait_ref_data(&self, trait_ref: &ast::TraitRef) -> Option<Ref> {
-        self.lookup_def_id(trait_ref.ref_id).and_then(|def_id| {
+    pub fn get_trait_ref_data(&self, trait_ref: &hir::TraitRef<'_>) -> Option<Ref> {
+        self.lookup_def_id(trait_ref.hir_ref_id).and_then(|def_id| {
             let span = trait_ref.path.span;
             if generated_code(span) {
                 return None;
@@ -525,22 +494,20 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
         })
     }
 
-    pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
-        let expr_hir_id = self.tcx.hir().node_id_to_hir_id(expr.id);
-        let hir_node = self.tcx.hir().expect_expr(expr_hir_id);
+    pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option<Data> {
+        let hir_node = self.tcx.hir().expect_expr(expr.hir_id);
         let ty = self.tables.expr_ty_adjusted_opt(&hir_node);
         if ty.is_none() || ty.unwrap().kind == ty::Error {
             return None;
         }
         match expr.kind {
-            ast::ExprKind::Field(ref sub_ex, ident) => {
-                let sub_ex_hir_id = self.tcx.hir().node_id_to_hir_id(sub_ex.id);
-                let hir_node = match self.tcx.hir().find(sub_ex_hir_id) {
+            hir::ExprKind::Field(ref sub_ex, ident) => {
+                let hir_node = match self.tcx.hir().find(sub_ex.hir_id) {
                     Some(Node::Expr(expr)) => expr,
                     _ => {
                         debug!(
                             "Missing or weird node for sub-expression {} in {:?}",
-                            sub_ex.id, expr
+                            sub_ex.hir_id, expr
                         );
                         return None;
                     }
@@ -567,7 +534,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
                     }
                 }
             }
-            ast::ExprKind::Struct(ref path, ..) => {
+            hir::ExprKind::Struct(hir::QPath::Resolved(_, path), ..) => {
                 match self.tables.expr_ty_adjusted(&hir_node).kind {
                     ty::Adt(def, _) if !def.is_enum() => {
                         let sub_span = path.segments.last().unwrap().ident.span;
@@ -587,9 +554,8 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
                     }
                 }
             }
-            ast::ExprKind::MethodCall(ref seg, ..) => {
-                let expr_hir_id = self.tcx.hir().definitions().node_id_to_hir_id(expr.id);
-                let method_id = match self.tables.type_dependent_def_id(expr_hir_id) {
+            hir::ExprKind::MethodCall(ref seg, ..) => {
+                let method_id = match self.tables.type_dependent_def_id(expr.hir_id) {
                     Some(id) => id,
                     None => {
                         debug!("could not resolve method id for {:?}", expr);
@@ -609,8 +575,8 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
                     ref_id: def_id.or(decl_id).map(id_from_def_id).unwrap_or_else(null_id),
                 }))
             }
-            ast::ExprKind::Path(_, ref path) => {
-                self.get_path_data(expr.id, path).map(Data::RefData)
+            hir::ExprKind::Path(hir::QPath::Resolved(_, path)) => {
+                self.get_path_data(expr.hir_id, path).map(Data::RefData)
             }
             _ => {
                 // FIXME
@@ -619,12 +585,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
         }
     }
 
-    pub fn get_path_res(&self, id: NodeId) -> Res {
-        // FIXME(#71104)
-        let hir_id = match self.tcx.hir().opt_node_id_to_hir_id(id) {
-            Some(id) => id,
-            None => return Res::Err,
-        };
+    pub fn get_path_res(&self, hir_id: hir::HirId) -> Res {
         match self.tcx.hir().get(hir_id) {
             Node::TraitRef(tr) => tr.path.res,
 
@@ -638,7 +599,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
                 Some(res) if res != Res::Err => res,
                 _ => {
                     let parent_node = self.tcx.hir().get_parent_node(hir_id);
-                    self.get_path_res(self.tcx.hir().hir_id_to_node_id(parent_node))
+                    self.get_path_res(parent_node)
                 }
             },
 
@@ -666,33 +627,24 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
         }
     }
 
-    pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Ref> {
+    pub fn get_path_data(&self, id: hir::HirId, path: &hir::Path<'_>) -> Option<Ref> {
         path.segments.last().and_then(|seg| {
             self.get_path_segment_data(seg).or_else(|| self.get_path_segment_data_with_id(seg, id))
         })
     }
 
-    pub fn get_path_segment_data(&self, path_seg: &ast::PathSegment) -> Option<Ref> {
-        self.get_path_segment_data_with_id(path_seg, path_seg.id)
+    pub fn get_path_segment_data(&self, path_seg: &hir::PathSegment<'_>) -> Option<Ref> {
+        self.get_path_segment_data_with_id(path_seg, path_seg.hir_id?)
     }
 
-    fn get_path_segment_data_with_id(
+    pub fn get_path_segment_data_with_id(
         &self,
-        path_seg: &ast::PathSegment,
-        id: NodeId,
+        path_seg: &hir::PathSegment<'_>,
+        id: hir::HirId,
     ) -> Option<Ref> {
         // Returns true if the path is function type sugar, e.g., `Fn(A) -> B`.
-        fn fn_type(seg: &ast::PathSegment) -> bool {
-            if let Some(ref generic_args) = seg.args {
-                if let ast::GenericArgs::Parenthesized(_) = **generic_args {
-                    return true;
-                }
-            }
-            false
-        }
-
-        if id == DUMMY_NODE_ID {
-            return None;
+        fn fn_type(seg: &hir::PathSegment<'_>) -> bool {
+            seg.args.map(|args| args.parenthesized).unwrap_or(false)
         }
 
         let res = self.get_path_res(id);
@@ -701,11 +653,9 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
         let span = self.span_from_span(span);
 
         match res {
-            Res::Local(id) => Some(Ref {
-                kind: RefKind::Variable,
-                span,
-                ref_id: id_from_node_id(self.tcx.hir().hir_id_to_node_id(id), self),
-            }),
+            Res::Local(id) => {
+                Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_hir_id(id, self) })
+            }
             Res::Def(HirDefKind::Trait, def_id) if fn_type(path_seg) => {
                 Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(def_id) })
             }
@@ -791,7 +741,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
 
     pub fn get_field_ref_data(
         &self,
-        field_ref: &ast::Field,
+        field_ref: &hir::Field<'_>,
         variant: &ty::VariantDef,
     ) -> Option<Ref> {
         filter!(self.span_utils, field_ref.ident.span);
@@ -839,14 +789,14 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
         })
     }
 
-    fn lookup_def_id(&self, ref_id: NodeId) -> Option<DefId> {
+    fn lookup_def_id(&self, ref_id: hir::HirId) -> Option<DefId> {
         match self.get_path_res(ref_id) {
             Res::PrimTy(_) | Res::SelfTy(..) | Res::Err => None,
             def => def.opt_def_id(),
         }
     }
 
-    fn docs_for_attrs(&self, attrs: &[Attribute]) -> String {
+    fn docs_for_attrs(&self, attrs: &[ast::Attribute]) -> String {
         let mut result = String::new();
 
         for attr in attrs {
@@ -890,7 +840,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
     }
 }
 
-fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String {
+fn make_signature(decl: &hir::FnDecl<'_>, generics: &hir::Generics<'_>) -> String {
     let mut sig = "fn ".to_owned();
     if !generics.params.is_empty() {
         sig.push('<');
@@ -898,18 +848,18 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String {
             &generics
                 .params
                 .iter()
-                .map(|param| param.ident.to_string())
+                .map(|param| param.name.ident().to_string())
                 .collect::<Vec<_>>()
                 .join(", "),
         );
         sig.push_str("> ");
     }
     sig.push('(');
-    sig.push_str(&decl.inputs.iter().map(param_to_string).collect::<Vec<_>>().join(", "));
+    sig.push_str(&decl.inputs.iter().map(ty_to_string).collect::<Vec<_>>().join(", "));
     sig.push(')');
     match decl.output {
-        ast::FnRetTy::Default(_) => sig.push_str(" -> ()"),
-        ast::FnRetTy::Ty(ref t) => sig.push_str(&format!(" -> {}", ty_to_string(t))),
+        hir::FnRetTy::DefaultReturn(_) => sig.push_str(" -> ()"),
+        hir::FnRetTy::Return(ref t) => sig.push_str(&format!(" -> {}", ty_to_string(t))),
     }
 
     sig
@@ -918,26 +868,33 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String {
 // An AST visitor for collecting paths (e.g., the names of structs) and formal
 // variables (idents) from patterns.
 struct PathCollector<'l> {
-    collected_paths: Vec<(NodeId, &'l ast::Path)>,
-    collected_idents: Vec<(NodeId, Ident, ast::Mutability)>,
+    tcx: TyCtxt<'l>,
+    collected_paths: Vec<(hir::HirId, &'l hir::QPath<'l>)>,
+    collected_idents: Vec<(hir::HirId, Ident, hir::Mutability)>,
 }
 
 impl<'l> PathCollector<'l> {
-    fn new() -> PathCollector<'l> {
-        PathCollector { collected_paths: vec![], collected_idents: vec![] }
+    fn new(tcx: TyCtxt<'l>) -> PathCollector<'l> {
+        PathCollector { tcx, collected_paths: vec![], collected_idents: vec![] }
     }
 }
 
 impl<'l> Visitor<'l> for PathCollector<'l> {
-    fn visit_pat(&mut self, p: &'l ast::Pat) {
+    type Map = Map<'l>;
+
+    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+        intravisit::NestedVisitorMap::All(self.tcx.hir())
+    }
+
+    fn visit_pat(&mut self, p: &'l hir::Pat<'l>) {
         match p.kind {
-            PatKind::Struct(ref path, ..) => {
-                self.collected_paths.push((p.id, path));
+            hir::PatKind::Struct(ref path, ..) => {
+                self.collected_paths.push((p.hir_id, path));
             }
-            PatKind::TupleStruct(ref path, ..) | PatKind::Path(_, ref path) => {
-                self.collected_paths.push((p.id, path));
+            hir::PatKind::TupleStruct(ref path, ..) | hir::PatKind::Path(ref path) => {
+                self.collected_paths.push((p.hir_id, path));
             }
-            PatKind::Ident(bm, ident, _) => {
+            hir::PatKind::Binding(bm, _, ident, _) => {
                 debug!(
                     "PathCollector, visit ident in pat {}: {:?} {:?}",
                     ident, p.span, ident.span
@@ -946,14 +903,18 @@ impl<'l> Visitor<'l> for PathCollector<'l> {
                     // Even if the ref is mut, you can't change the ref, only
                     // the data pointed at, so showing the initialising expression
                     // is still worthwhile.
-                    ast::BindingMode::ByRef(_) => ast::Mutability::Not,
-                    ast::BindingMode::ByValue(mt) => mt,
+                    hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Ref => {
+                        hir::Mutability::Not
+                    }
+                    hir::BindingAnnotation::Mutable | hir::BindingAnnotation::RefMut => {
+                        hir::Mutability::Mut
+                    }
                 };
-                self.collected_idents.push((p.id, ident, immut));
+                self.collected_idents.push((p.hir_id, ident, immut));
             }
             _ => {}
         }
-        visit::walk_pat(self, p);
+        intravisit::walk_pat(self, p);
     }
 }
 
@@ -1035,7 +996,6 @@ impl SaveHandler for CallbackHandler<'_> {
 
 pub fn process_crate<'l, 'tcx, H: SaveHandler>(
     tcx: TyCtxt<'tcx>,
-    krate: &ast::Crate,
     cratename: &str,
     input: &'l Input,
     config: Option<Config>,
@@ -1063,9 +1023,9 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>(
 
         let mut visitor = DumpVisitor::new(save_ctxt);
 
-        visitor.dump_crate_info(cratename, krate);
+        visitor.dump_crate_info(cratename, tcx.hir().krate());
         visitor.dump_compilation_options(input, cratename);
-        visit::walk_crate(&mut visitor, krate);
+        visitor.process_crate(tcx.hir().krate());
 
         handler.save(&visitor.save_ctxt, &visitor.analysis())
     })
@@ -1109,13 +1069,17 @@ fn id_from_def_id(id: DefId) -> rls_data::Id {
     rls_data::Id { krate: id.krate.as_u32(), index: id.index.as_u32() }
 }
 
-fn id_from_node_id(id: NodeId, scx: &SaveContext<'_, '_>) -> rls_data::Id {
-    let def_id = scx.tcx.hir().opt_local_def_id_from_node_id(id);
+fn id_from_hir_id(id: hir::HirId, scx: &SaveContext<'_, '_>) -> rls_data::Id {
+    let def_id = scx.tcx.hir().opt_local_def_id(id);
     def_id.map(|id| id_from_def_id(id.to_def_id())).unwrap_or_else(|| {
-        // Create a *fake* `DefId` out of a `NodeId` by subtracting the `NodeId`
-        // out of the maximum u32 value. This will work unless you have *billions*
-        // of definitions in a single crate (very unlikely to actually happen).
-        rls_data::Id { krate: LOCAL_CRATE.as_u32(), index: !id.as_u32() }
+        // Create a *fake* `DefId` out of a `HirId` by combining the owner
+        // `local_def_index` and the `local_id`.
+        // This will work unless you have *billions* of definitions in a single
+        // crate (very unlikely to actually happen).
+        rls_data::Id {
+            krate: LOCAL_CRATE.as_u32(),
+            index: id.owner.local_def_index.as_u32() | id.local_id.as_u32().reverse_bits(),
+        }
     })
 }
 
@@ -1123,7 +1087,10 @@ fn null_id() -> rls_data::Id {
     rls_data::Id { krate: u32::max_value(), index: u32::max_value() }
 }
 
-fn lower_attributes(attrs: Vec<Attribute>, scx: &SaveContext<'_, '_>) -> Vec<rls_data::Attribute> {
+fn lower_attributes(
+    attrs: Vec<ast::Attribute>,
+    scx: &SaveContext<'_, '_>,
+) -> Vec<rls_data::Attribute> {
     attrs
         .into_iter()
         // Only retain real attributes. Doc comments are lowered separately.
@@ -1133,7 +1100,7 @@ fn lower_attributes(attrs: Vec<Attribute>, scx: &SaveContext<'_, '_>) -> Vec<rls
             // attribute. First normalize all inner attribute (#![..]) to outer
             // ones (#[..]), then remove the two leading and the one trailing character.
             attr.style = ast::AttrStyle::Outer;
-            let value = pprust::attribute_to_string(&attr);
+            let value = attribute_to_string(&attr);
             // This str slicing works correctly, because the leading and trailing characters
             // are in the ASCII range and thus exactly one byte each.
             let value = value[2..value.len() - 1].to_string();
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index bda9ff93b02..6fec5cdba8b 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -25,16 +25,18 @@
 //
 // FIXME where clauses need implementing, defs/refs in generics are mostly missing.
 
-use crate::{id_from_def_id, id_from_node_id, SaveContext};
+use crate::{id_from_def_id, id_from_hir_id, SaveContext};
 
 use rls_data::{SigElement, Signature};
 
-use rustc_ast::ast::{self, Extern, NodeId};
-use rustc_ast_pretty::pprust;
+use rustc_ast::ast::Mutability;
+use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
+use rustc_hir_pretty::id_to_string;
+use rustc_hir_pretty::{bounds_to_string, path_segment_to_string, path_to_string, ty_to_string};
 use rustc_span::symbol::{Ident, Symbol};
 
-pub fn item_signature(item: &ast::Item, scx: &SaveContext<'_, '_>) -> Option<Signature> {
+pub fn item_signature(item: &hir::Item<'_>, scx: &SaveContext<'_, '_>) -> Option<Signature> {
     if !scx.config.signatures {
         return None;
     }
@@ -42,7 +44,7 @@ pub fn item_signature(item: &ast::Item, scx: &SaveContext<'_, '_>) -> Option<Sig
 }
 
 pub fn foreign_item_signature(
-    item: &ast::ForeignItem,
+    item: &hir::ForeignItem<'_>,
     scx: &SaveContext<'_, '_>,
 ) -> Option<Signature> {
     if !scx.config.signatures {
@@ -53,7 +55,10 @@ pub fn foreign_item_signature(
 
 /// Signature for a struct or tuple field declaration.
 /// Does not include a trailing comma.
-pub fn field_signature(field: &ast::StructField, scx: &SaveContext<'_, '_>) -> Option<Signature> {
+pub fn field_signature(
+    field: &hir::StructField<'_>,
+    scx: &SaveContext<'_, '_>,
+) -> Option<Signature> {
     if !scx.config.signatures {
         return None;
     }
@@ -61,7 +66,10 @@ pub fn field_signature(field: &ast::StructField, scx: &SaveContext<'_, '_>) -> O
 }
 
 /// Does not include a trailing comma.
-pub fn variant_signature(variant: &ast::Variant, scx: &SaveContext<'_, '_>) -> Option<Signature> {
+pub fn variant_signature(
+    variant: &hir::Variant<'_>,
+    scx: &SaveContext<'_, '_>,
+) -> Option<Signature> {
     if !scx.config.signatures {
         return None;
     }
@@ -69,10 +77,10 @@ pub fn variant_signature(variant: &ast::Variant, scx: &SaveContext<'_, '_>) -> O
 }
 
 pub fn method_signature(
-    id: NodeId,
+    id: hir::HirId,
     ident: Ident,
-    generics: &ast::Generics,
-    m: &ast::FnSig,
+    generics: &hir::Generics<'_>,
+    m: &hir::FnSig<'_>,
     scx: &SaveContext<'_, '_>,
 ) -> Option<Signature> {
     if !scx.config.signatures {
@@ -82,10 +90,10 @@ pub fn method_signature(
 }
 
 pub fn assoc_const_signature(
-    id: NodeId,
+    id: hir::HirId,
     ident: Symbol,
-    ty: &ast::Ty,
-    default: Option<&ast::Expr>,
+    ty: &hir::Ty<'_>,
+    default: Option<&hir::Expr<'_>>,
     scx: &SaveContext<'_, '_>,
 ) -> Option<Signature> {
     if !scx.config.signatures {
@@ -95,10 +103,10 @@ pub fn assoc_const_signature(
 }
 
 pub fn assoc_type_signature(
-    id: NodeId,
+    id: hir::HirId,
     ident: Ident,
-    bounds: Option<&ast::GenericBounds>,
-    default: Option<&ast::Ty>,
+    bounds: Option<hir::GenericBounds<'_>>,
+    default: Option<&hir::Ty<'_>>,
     scx: &SaveContext<'_, '_>,
 ) -> Option<Signature> {
     if !scx.config.signatures {
@@ -110,7 +118,7 @@ pub fn assoc_type_signature(
 type Result = std::result::Result<Signature, &'static str>;
 
 trait Sig {
-    fn make(&self, offset: usize, id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result;
+    fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_, '_>) -> Result;
 }
 
 fn extend_sig(
@@ -145,39 +153,34 @@ fn text_sig(text: String) -> Signature {
     Signature { text, defs: vec![], refs: vec![] }
 }
 
-fn push_extern(text: &mut String, ext: Extern) {
-    match ext {
-        Extern::None => {}
-        Extern::Implicit => text.push_str("extern "),
-        Extern::Explicit(abi) => text.push_str(&format!("extern \"{}\" ", abi.symbol)),
-    }
-}
-
-impl Sig for ast::Ty {
-    fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
-        let id = Some(self.id);
+impl<'hir> Sig for hir::Ty<'hir> {
+    fn make(
+        &self,
+        offset: usize,
+        _parent_id: Option<hir::HirId>,
+        scx: &SaveContext<'_, '_>,
+    ) -> Result {
+        let id = Some(self.hir_id);
         match self.kind {
-            ast::TyKind::Slice(ref ty) => {
+            hir::TyKind::Slice(ref ty) => {
                 let nested = ty.make(offset + 1, id, scx)?;
                 let text = format!("[{}]", nested.text);
                 Ok(replace_text(nested, text))
             }
-            ast::TyKind::Ptr(ref mt) => {
+            hir::TyKind::Ptr(ref mt) => {
                 let prefix = match mt.mutbl {
-                    ast::Mutability::Mut => "*mut ",
-                    ast::Mutability::Not => "*const ",
+                    hir::Mutability::Mut => "*mut ",
+                    hir::Mutability::Not => "*const ",
                 };
                 let nested = mt.ty.make(offset + prefix.len(), id, scx)?;
                 let text = format!("{}{}", prefix, nested.text);
                 Ok(replace_text(nested, text))
             }
-            ast::TyKind::Rptr(ref lifetime, ref mt) => {
+            hir::TyKind::Rptr(ref lifetime, ref mt) => {
                 let mut prefix = "&".to_owned();
-                if let &Some(ref l) = lifetime {
-                    prefix.push_str(&l.ident.to_string());
-                    prefix.push(' ');
-                }
-                if let ast::Mutability::Mut = mt.mutbl {
+                prefix.push_str(&lifetime.name.ident().to_string());
+                prefix.push(' ');
+                if let hir::Mutability::Mut = mt.mutbl {
                     prefix.push_str("mut ");
                 };
 
@@ -185,9 +188,8 @@ impl Sig for ast::Ty {
                 let text = format!("{}{}", prefix, nested.text);
                 Ok(replace_text(nested, text))
             }
-            ast::TyKind::Never => Ok(text_sig("!".to_owned())),
-            ast::TyKind::CVarArgs => Ok(text_sig("...".to_owned())),
-            ast::TyKind::Tup(ref ts) => {
+            hir::TyKind::Never => Ok(text_sig("!".to_owned())),
+            hir::TyKind::Tup(ts) => {
                 let mut text = "(".to_owned();
                 let mut defs = vec![];
                 let mut refs = vec![];
@@ -201,12 +203,7 @@ impl Sig for ast::Ty {
                 text.push(')');
                 Ok(Signature { text, defs, refs })
             }
-            ast::TyKind::Paren(ref ty) => {
-                let nested = ty.make(offset + 1, id, scx)?;
-                let text = format!("({})", nested.text);
-                Ok(replace_text(nested, text))
-            }
-            ast::TyKind::BareFn(ref f) => {
+            hir::TyKind::BareFn(ref f) => {
                 let mut text = String::new();
                 if !f.generic_params.is_empty() {
                     // FIXME defs, bounds on lifetimes
@@ -215,8 +212,8 @@ impl Sig for ast::Ty {
                         &f.generic_params
                             .iter()
                             .filter_map(|param| match param.kind {
-                                ast::GenericParamKind::Lifetime { .. } => {
-                                    Some(param.ident.to_string())
+                                hir::GenericParamKind::Lifetime { .. } => {
+                                    Some(param.name.ident().to_string())
                                 }
                                 _ => None,
                             })
@@ -226,23 +223,22 @@ impl Sig for ast::Ty {
                     text.push('>');
                 }
 
-                if let ast::Unsafe::Yes(_) = f.unsafety {
+                if let hir::Unsafety::Unsafe = f.unsafety {
                     text.push_str("unsafe ");
                 }
-                push_extern(&mut text, f.ext);
                 text.push_str("fn(");
 
                 let mut defs = vec![];
                 let mut refs = vec![];
-                for i in &f.decl.inputs {
-                    let nested = i.ty.make(offset + text.len(), Some(i.id), scx)?;
+                for i in f.decl.inputs {
+                    let nested = i.make(offset + text.len(), Some(i.hir_id), scx)?;
                     text.push_str(&nested.text);
                     text.push(',');
                     defs.extend(nested.defs.into_iter());
                     refs.extend(nested.refs.into_iter());
                 }
                 text.push(')');
-                if let ast::FnRetTy::Ty(ref t) = f.decl.output {
+                if let hir::FnRetTy::Return(ref t) = f.decl.output {
                     text.push_str(" -> ");
                     let nested = t.make(offset + text.len(), None, scx)?;
                     text.push_str(&nested.text);
@@ -253,23 +249,19 @@ impl Sig for ast::Ty {
 
                 Ok(Signature { text, defs, refs })
             }
-            ast::TyKind::Path(None, ref path) => path.make(offset, id, scx),
-            ast::TyKind::Path(Some(ref qself), ref path) => {
-                let nested_ty = qself.ty.make(offset + 1, id, scx)?;
-                let prefix = if qself.position == 0 {
-                    format!("<{}>::", nested_ty.text)
-                } else if qself.position == 1 {
-                    let first = pprust::path_segment_to_string(&path.segments[0]);
-                    format!("<{} as {}>::", nested_ty.text, first)
-                } else {
-                    // FIXME handle path instead of elipses.
-                    format!("<{} as ...>::", nested_ty.text)
-                };
+            hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.make(offset, id, scx),
+            hir::TyKind::Path(hir::QPath::Resolved(Some(ref qself), ref path)) => {
+                let nested_ty = qself.make(offset + 1, id, scx)?;
+                let prefix = format!(
+                    "<{} as {}>::",
+                    nested_ty.text,
+                    path_segment_to_string(&path.segments[0])
+                );
 
-                let name = pprust::path_segment_to_string(path.segments.last().ok_or("Bad path")?);
+                let name = path_segment_to_string(path.segments.last().ok_or("Bad path")?);
                 let res = scx.get_path_res(id.ok_or("Missing id for Path")?);
                 let id = id_from_def_id(res.def_id());
-                if path.segments.len() - qself.position == 1 {
+                if path.segments.len() == 2 {
                     let start = offset + prefix.len();
                     let end = start + name.len();
 
@@ -289,44 +281,60 @@ impl Sig for ast::Ty {
                     })
                 }
             }
-            ast::TyKind::TraitObject(ref bounds, ..) => {
+            hir::TyKind::TraitObject(bounds, ..) => {
                 // FIXME recurse into bounds
-                let nested = pprust::bounds_to_string(bounds);
+                let bounds: Vec<hir::GenericBound<'_>> = bounds
+                    .iter()
+                    .map(|hir::PolyTraitRef { bound_generic_params, trait_ref, span }| {
+                        hir::GenericBound::Trait(
+                            hir::PolyTraitRef {
+                                bound_generic_params,
+                                trait_ref: hir::TraitRef {
+                                    path: trait_ref.path,
+                                    hir_ref_id: trait_ref.hir_ref_id,
+                                },
+                                span: *span,
+                            },
+                            hir::TraitBoundModifier::None,
+                        )
+                    })
+                    .collect();
+                let nested = bounds_to_string(&bounds);
                 Ok(text_sig(nested))
             }
-            ast::TyKind::ImplTrait(_, ref bounds) => {
-                // FIXME recurse into bounds
-                let nested = pprust::bounds_to_string(bounds);
-                Ok(text_sig(format!("impl {}", nested)))
-            }
-            ast::TyKind::Array(ref ty, ref v) => {
+            hir::TyKind::Array(ref ty, ref anon_const) => {
                 let nested_ty = ty.make(offset + 1, id, scx)?;
-                let expr = pprust::expr_to_string(&v.value).replace('\n', " ");
+                let expr = id_to_string(&scx.tcx.hir(), anon_const.body.hir_id).replace('\n', " ");
                 let text = format!("[{}; {}]", nested_ty.text, expr);
                 Ok(replace_text(nested_ty, text))
             }
-            ast::TyKind::Typeof(_)
-            | ast::TyKind::Infer
-            | ast::TyKind::Err
-            | ast::TyKind::ImplicitSelf
-            | ast::TyKind::MacCall(_) => Err("Ty"),
+            hir::TyKind::Typeof(_)
+            | hir::TyKind::Infer
+            | hir::TyKind::Def(..)
+            | hir::TyKind::Path(..)
+            | hir::TyKind::Err => Err("Ty"),
         }
     }
 }
 
-impl Sig for ast::Item {
-    fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
-        let id = Some(self.id);
+impl<'hir> Sig for hir::Item<'hir> {
+    fn make(
+        &self,
+        offset: usize,
+        _parent_id: Option<hir::HirId>,
+        scx: &SaveContext<'_, '_>,
+    ) -> Result {
+        let id = Some(self.hir_id);
 
         match self.kind {
-            ast::ItemKind::Static(ref ty, m, ref expr) => {
+            hir::ItemKind::Static(ref ty, m, ref body) => {
                 let mut text = "static ".to_owned();
-                if m == ast::Mutability::Mut {
+                if m == hir::Mutability::Mut {
                     text.push_str("mut ");
                 }
                 let name = self.ident.to_string();
                 let defs = vec![SigElement {
-                    id: id_from_node_id(self.id, scx),
+                    id: id_from_hir_id(self.hir_id, scx),
                     start: offset + text.len(),
                     end: offset + text.len() + name.len(),
                 }];
@@ -336,21 +344,19 @@ impl Sig for ast::Item {
                 let ty = ty.make(offset + text.len(), id, scx)?;
                 text.push_str(&ty.text);
 
-                if let Some(expr) = expr {
-                    text.push_str(" = ");
-                    let expr = pprust::expr_to_string(expr).replace('\n', " ");
-                    text.push_str(&expr);
-                }
+                text.push_str(" = ");
+                let expr = id_to_string(&scx.tcx.hir(), body.hir_id).replace('\n', " ");
+                text.push_str(&expr);
 
                 text.push(';');
 
                 Ok(extend_sig(ty, text, defs, vec![]))
             }
-            ast::ItemKind::Const(_, ref ty, ref expr) => {
+            hir::ItemKind::Const(ref ty, ref body) => {
                 let mut text = "const ".to_owned();
                 let name = self.ident.to_string();
                 let defs = vec![SigElement {
-                    id: id_from_node_id(self.id, scx),
+                    id: id_from_hir_id(self.hir_id, scx),
                     start: offset + text.len(),
                     end: offset + text.len() + name.len(),
                 }];
@@ -360,38 +366,35 @@ impl Sig for ast::Item {
                 let ty = ty.make(offset + text.len(), id, scx)?;
                 text.push_str(&ty.text);
 
-                if let Some(expr) = expr {
-                    text.push_str(" = ");
-                    let expr = pprust::expr_to_string(expr).replace('\n', " ");
-                    text.push_str(&expr);
-                }
+                text.push_str(" = ");
+                let expr = id_to_string(&scx.tcx.hir(), body.hir_id).replace('\n', " ");
+                text.push_str(&expr);
 
                 text.push(';');
 
                 Ok(extend_sig(ty, text, defs, vec![]))
             }
-            ast::ItemKind::Fn(_, ast::FnSig { ref decl, header }, ref generics, _) => {
+            hir::ItemKind::Fn(hir::FnSig { ref decl, header }, ref generics, _) => {
                 let mut text = String::new();
-                if let ast::Const::Yes(_) = header.constness {
+                if let hir::Constness::Const = header.constness {
                     text.push_str("const ");
                 }
-                if header.asyncness.is_async() {
+                if hir::IsAsync::Async == header.asyncness {
                     text.push_str("async ");
                 }
-                if let ast::Unsafe::Yes(_) = header.unsafety {
+                if let hir::Unsafety::Unsafe = header.unsafety {
                     text.push_str("unsafe ");
                 }
-                push_extern(&mut text, header.ext);
                 text.push_str("fn ");
 
-                let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
+                let mut sig =
+                    name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?;
 
                 sig.text.push('(');
-                for i in &decl.inputs {
+                for i in decl.inputs {
                     // FIXME should descend into patterns to add defs.
-                    sig.text.push_str(&pprust::pat_to_string(&i.pat));
                     sig.text.push_str(": ");
-                    let nested = i.ty.make(offset + sig.text.len(), Some(i.id), scx)?;
+                    let nested = i.make(offset + sig.text.len(), Some(i.hir_id), scx)?;
                     sig.text.push_str(&nested.text);
                     sig.text.push(',');
                     sig.defs.extend(nested.defs.into_iter());
@@ -399,7 +402,7 @@ impl Sig for ast::Item {
                 }
                 sig.text.push(')');
 
-                if let ast::FnRetTy::Ty(ref t) = decl.output {
+                if let hir::FnRetTy::Return(ref t) = decl.output {
                     sig.text.push_str(" -> ");
                     let nested = t.make(offset + sig.text.len(), None, scx)?;
                     sig.text.push_str(&nested.text);
@@ -410,11 +413,11 @@ impl Sig for ast::Item {
 
                 Ok(sig)
             }
-            ast::ItemKind::Mod(ref _mod) => {
+            hir::ItemKind::Mod(ref _mod) => {
                 let mut text = "mod ".to_owned();
                 let name = self.ident.to_string();
                 let defs = vec![SigElement {
-                    id: id_from_node_id(self.id, scx),
+                    id: id_from_hir_id(self.hir_id, scx),
                     start: offset + text.len(),
                     end: offset + text.len() + name.len(),
                 }];
@@ -424,78 +427,82 @@ impl Sig for ast::Item {
 
                 Ok(Signature { text, defs, refs: vec![] })
             }
-            ast::ItemKind::TyAlias(_, ref generics, _, ref ty) => {
+            hir::ItemKind::TyAlias(ref ty, ref generics) => {
                 let text = "type ".to_owned();
-                let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
+                let mut sig =
+                    name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?;
 
                 sig.text.push_str(" = ");
-                let ty = match ty {
-                    Some(ty) => ty.make(offset + sig.text.len(), id, scx)?,
-                    None => return Err("Ty"),
-                };
+                let ty = ty.make(offset + sig.text.len(), id, scx)?;
                 sig.text.push_str(&ty.text);
                 sig.text.push(';');
 
                 Ok(merge_sigs(sig.text.clone(), vec![sig, ty]))
             }
-            ast::ItemKind::Enum(_, ref generics) => {
+            hir::ItemKind::Enum(_, ref generics) => {
                 let text = "enum ".to_owned();
-                let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
+                let mut sig =
+                    name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?;
                 sig.text.push_str(" {}");
                 Ok(sig)
             }
-            ast::ItemKind::Struct(_, ref generics) => {
+            hir::ItemKind::Struct(_, ref generics) => {
                 let text = "struct ".to_owned();
-                let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
+                let mut sig =
+                    name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?;
                 sig.text.push_str(" {}");
                 Ok(sig)
             }
-            ast::ItemKind::Union(_, ref generics) => {
+            hir::ItemKind::Union(_, ref generics) => {
                 let text = "union ".to_owned();
-                let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
+                let mut sig =
+                    name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?;
                 sig.text.push_str(" {}");
                 Ok(sig)
             }
-            ast::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, _) => {
+            hir::ItemKind::Trait(is_auto, unsafety, ref generics, bounds, _) => {
                 let mut text = String::new();
 
-                if is_auto == ast::IsAuto::Yes {
+                if is_auto == hir::IsAuto::Yes {
                     text.push_str("auto ");
                 }
 
-                if let ast::Unsafe::Yes(_) = unsafety {
+                if let hir::Unsafety::Unsafe = unsafety {
                     text.push_str("unsafe ");
                 }
                 text.push_str("trait ");
-                let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
+                let mut sig =
+                    name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?;
 
                 if !bounds.is_empty() {
                     sig.text.push_str(": ");
-                    sig.text.push_str(&pprust::bounds_to_string(bounds));
+                    sig.text.push_str(&bounds_to_string(bounds));
                 }
                 // FIXME where clause
                 sig.text.push_str(" {}");
 
                 Ok(sig)
             }
-            ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
+            hir::ItemKind::TraitAlias(ref generics, bounds) => {
                 let mut text = String::new();
                 text.push_str("trait ");
-                let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
+                let mut sig =
+                    name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?;
 
                 if !bounds.is_empty() {
                     sig.text.push_str(" = ");
-                    sig.text.push_str(&pprust::bounds_to_string(bounds));
+                    sig.text.push_str(&bounds_to_string(bounds));
                 }
                 // FIXME where clause
                 sig.text.push_str(";");
 
                 Ok(sig)
             }
-            ast::ItemKind::Impl {
+            hir::ItemKind::Impl {
                 unsafety,
                 polarity,
                 defaultness,
+                defaultness_span: _,
                 constness,
                 ref generics,
                 ref of_trait,
@@ -503,14 +510,14 @@ impl Sig for ast::Item {
                 items: _,
             } => {
                 let mut text = String::new();
-                if let ast::Defaultness::Default(_) = defaultness {
+                if let hir::Defaultness::Default { .. } = defaultness {
                     text.push_str("default ");
                 }
-                if let ast::Unsafe::Yes(_) = unsafety {
+                if let hir::Unsafety::Unsafe = unsafety {
                     text.push_str("unsafe ");
                 }
                 text.push_str("impl");
-                if let ast::Const::Yes(_) = constness {
+                if let hir::Constness::Const = constness {
                     text.push_str(" const");
                 }
 
@@ -520,7 +527,7 @@ impl Sig for ast::Item {
                 text.push(' ');
 
                 let trait_sig = if let Some(ref t) = *of_trait {
-                    if let ast::ImplPolarity::Negative(_) = polarity {
+                    if let hir::ImplPolarity::Negative(_) = polarity {
                         text.push('!');
                     }
                     let trait_sig = t.path.make(offset + text.len(), id, scx)?;
@@ -540,27 +547,23 @@ impl Sig for ast::Item {
 
                 // FIXME where clause
             }
-            ast::ItemKind::ForeignMod(_) => Err("extern mod"),
-            ast::ItemKind::GlobalAsm(_) => Err("glboal asm"),
-            ast::ItemKind::ExternCrate(_) => Err("extern crate"),
+            hir::ItemKind::ForeignMod(_) => Err("extern mod"),
+            hir::ItemKind::GlobalAsm(_) => Err("glboal asm"),
+            hir::ItemKind::ExternCrate(_) => Err("extern crate"),
+            hir::ItemKind::OpaqueTy(..) => Err("opaque type"),
             // FIXME should implement this (e.g., pub use).
-            ast::ItemKind::Use(_) => Err("import"),
-            ast::ItemKind::MacCall(..) | ast::ItemKind::MacroDef(_) => Err("Macro"),
+            hir::ItemKind::Use(..) => Err("import"),
         }
     }
 }
 
-impl Sig for ast::Path {
-    fn make(&self, offset: usize, id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
+impl<'hir> Sig for hir::Path<'hir> {
+    fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_, '_>) -> Result {
         let res = scx.get_path_res(id.ok_or("Missing id for Path")?);
 
         let (name, start, end) = match res {
             Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => {
-                return Ok(Signature {
-                    text: pprust::path_to_string(self),
-                    defs: vec![],
-                    refs: vec![],
-                });
+                return Ok(Signature { text: path_to_string(self), defs: vec![], refs: vec![] });
             }
             Res::Def(DefKind::AssocConst | DefKind::Variant | DefKind::Ctor(..), _) => {
                 let len = self.segments.len();
@@ -570,13 +573,13 @@ impl Sig for ast::Path {
                 // FIXME: really we should descend into the generics here and add SigElements for
                 // them.
                 // FIXME: would be nice to have a def for the first path segment.
-                let seg1 = pprust::path_segment_to_string(&self.segments[len - 2]);
-                let seg2 = pprust::path_segment_to_string(&self.segments[len - 1]);
+                let seg1 = path_segment_to_string(&self.segments[len - 2]);
+                let seg2 = path_segment_to_string(&self.segments[len - 1]);
                 let start = offset + seg1.len() + 2;
                 (format!("{}::{}", seg1, seg2), start, start + seg2.len())
             }
             _ => {
-                let name = pprust::path_segment_to_string(self.segments.last().ok_or("Bad path")?);
+                let name = path_segment_to_string(self.segments.last().ok_or("Bad path")?);
                 let end = offset + name.len();
                 (name, offset, end)
             }
@@ -588,8 +591,13 @@ impl Sig for ast::Path {
 }
 
 // This does not cover the where clause, which must be processed separately.
-impl Sig for ast::Generics {
-    fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
+impl<'hir> Sig for hir::Generics<'hir> {
+    fn make(
+        &self,
+        offset: usize,
+        _parent_id: Option<hir::HirId>,
+        scx: &SaveContext<'_, '_>,
+    ) -> Result {
         if self.params.is_empty() {
             return Ok(text_sig(String::new()));
         }
@@ -597,30 +605,30 @@ impl Sig for ast::Generics {
         let mut text = "<".to_owned();
 
         let mut defs = Vec::with_capacity(self.params.len());
-        for param in &self.params {
+        for param in self.params {
             let mut param_text = String::new();
-            if let ast::GenericParamKind::Const { .. } = param.kind {
+            if let hir::GenericParamKind::Const { .. } = param.kind {
                 param_text.push_str("const ");
             }
-            param_text.push_str(&param.ident.as_str());
+            param_text.push_str(&param.name.ident().as_str());
             defs.push(SigElement {
-                id: id_from_node_id(param.id, scx),
+                id: id_from_hir_id(param.hir_id, scx),
                 start: offset + text.len(),
                 end: offset + text.len() + param_text.as_str().len(),
             });
-            if let ast::GenericParamKind::Const { ref ty } = param.kind {
+            if let hir::GenericParamKind::Const { ref ty } = param.kind {
                 param_text.push_str(": ");
-                param_text.push_str(&pprust::ty_to_string(&ty));
+                param_text.push_str(&ty_to_string(&ty));
             }
             if !param.bounds.is_empty() {
                 param_text.push_str(": ");
                 match param.kind {
-                    ast::GenericParamKind::Lifetime { .. } => {
+                    hir::GenericParamKind::Lifetime { .. } => {
                         let bounds = param
                             .bounds
                             .iter()
                             .map(|bound| match bound {
-                                ast::GenericBound::Outlives(lt) => lt.ident.to_string(),
+                                hir::GenericBound::Outlives(lt) => lt.name.ident().to_string(),
                                 _ => panic!(),
                             })
                             .collect::<Vec<_>>()
@@ -628,11 +636,11 @@ impl Sig for ast::Generics {
                         param_text.push_str(&bounds);
                         // FIXME add lifetime bounds refs.
                     }
-                    ast::GenericParamKind::Type { .. } => {
-                        param_text.push_str(&pprust::bounds_to_string(&param.bounds));
+                    hir::GenericParamKind::Type { .. } => {
+                        param_text.push_str(&bounds_to_string(param.bounds));
                         // FIXME descend properly into bounds.
                     }
-                    ast::GenericParamKind::Const { .. } => {
+                    hir::GenericParamKind::Const { .. } => {
                         // Const generics cannot contain bounds.
                     }
                 }
@@ -646,21 +654,24 @@ impl Sig for ast::Generics {
     }
 }
 
-impl Sig for ast::StructField {
-    fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
+impl<'hir> Sig for hir::StructField<'hir> {
+    fn make(
+        &self,
+        offset: usize,
+        _parent_id: Option<hir::HirId>,
+        scx: &SaveContext<'_, '_>,
+    ) -> Result {
         let mut text = String::new();
-        let mut defs = None;
-        if let Some(ident) = self.ident {
-            text.push_str(&ident.to_string());
-            defs = Some(SigElement {
-                id: id_from_node_id(self.id, scx),
-                start: offset,
-                end: offset + text.len(),
-            });
-            text.push_str(": ");
-        }
 
-        let mut ty_sig = self.ty.make(offset + text.len(), Some(self.id), scx)?;
+        text.push_str(&self.ident.to_string());
+        let defs = Some(SigElement {
+            id: id_from_hir_id(self.hir_id, scx),
+            start: offset,
+            end: offset + text.len(),
+        });
+        text.push_str(": ");
+
+        let mut ty_sig = self.ty.make(offset + text.len(), Some(self.hir_id), scx)?;
         text.push_str(&ty_sig.text);
         ty_sig.text = text;
         ty_sig.defs.extend(defs.into_iter());
@@ -668,14 +679,19 @@ impl Sig for ast::StructField {
     }
 }
 
-impl Sig for ast::Variant {
-    fn make(&self, offset: usize, parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
+impl<'hir> Sig for hir::Variant<'hir> {
+    fn make(
+        &self,
+        offset: usize,
+        parent_id: Option<hir::HirId>,
+        scx: &SaveContext<'_, '_>,
+    ) -> Result {
         let mut text = self.ident.to_string();
         match self.data {
-            ast::VariantData::Struct(ref fields, r) => {
+            hir::VariantData::Struct(fields, r) => {
                 let id = parent_id.unwrap();
                 let name_def = SigElement {
-                    id: id_from_node_id(id, scx),
+                    id: id_from_hir_id(id, scx),
                     start: offset,
                     end: offset + text.len(),
                 };
@@ -696,9 +712,9 @@ impl Sig for ast::Variant {
                 text.push('}');
                 Ok(Signature { text, defs, refs })
             }
-            ast::VariantData::Tuple(ref fields, id) => {
+            hir::VariantData::Tuple(fields, id) => {
                 let name_def = SigElement {
-                    id: id_from_node_id(id, scx),
+                    id: id_from_hir_id(id, scx),
                     start: offset,
                     end: offset + text.len(),
                 };
@@ -715,9 +731,9 @@ impl Sig for ast::Variant {
                 text.push(')');
                 Ok(Signature { text, defs, refs })
             }
-            ast::VariantData::Unit(id) => {
+            hir::VariantData::Unit(id) => {
                 let name_def = SigElement {
-                    id: id_from_node_id(id, scx),
+                    id: id_from_hir_id(id, scx),
                     start: offset,
                     end: offset + text.len(),
                 };
@@ -727,23 +743,26 @@ impl Sig for ast::Variant {
     }
 }
 
-impl Sig for ast::ForeignItem {
-    fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
-        let id = Some(self.id);
+impl<'hir> Sig for hir::ForeignItem<'hir> {
+    fn make(
+        &self,
+        offset: usize,
+        _parent_id: Option<hir::HirId>,
+        scx: &SaveContext<'_, '_>,
+    ) -> Result {
+        let id = Some(self.hir_id);
         match self.kind {
-            ast::ForeignItemKind::Fn(_, ref sig, ref generics, _) => {
-                let decl = &sig.decl;
+            hir::ForeignItemKind::Fn(decl, _, ref generics) => {
                 let mut text = String::new();
                 text.push_str("fn ");
 
-                let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?;
+                let mut sig =
+                    name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?;
 
                 sig.text.push('(');
-                for i in &decl.inputs {
-                    // FIXME should descend into patterns to add defs.
-                    sig.text.push_str(&pprust::pat_to_string(&i.pat));
+                for i in decl.inputs {
                     sig.text.push_str(": ");
-                    let nested = i.ty.make(offset + sig.text.len(), Some(i.id), scx)?;
+                    let nested = i.make(offset + sig.text.len(), Some(i.hir_id), scx)?;
                     sig.text.push_str(&nested.text);
                     sig.text.push(',');
                     sig.defs.extend(nested.defs.into_iter());
@@ -751,7 +770,7 @@ impl Sig for ast::ForeignItem {
                 }
                 sig.text.push(')');
 
-                if let ast::FnRetTy::Ty(ref t) = decl.output {
+                if let hir::FnRetTy::Return(ref t) = decl.output {
                     sig.text.push_str(" -> ");
                     let nested = t.make(offset + sig.text.len(), None, scx)?;
                     sig.text.push_str(&nested.text);
@@ -762,14 +781,14 @@ impl Sig for ast::ForeignItem {
 
                 Ok(sig)
             }
-            ast::ForeignItemKind::Static(ref ty, m, _) => {
+            hir::ForeignItemKind::Static(ref ty, m) => {
                 let mut text = "static ".to_owned();
-                if m == ast::Mutability::Mut {
+                if m == Mutability::Mut {
                     text.push_str("mut ");
                 }
                 let name = self.ident.to_string();
                 let defs = vec![SigElement {
-                    id: id_from_node_id(self.id, scx),
+                    id: id_from_hir_id(self.hir_id, scx),
                     start: offset + text.len(),
                     end: offset + text.len() + name.len(),
                 }];
@@ -781,11 +800,11 @@ impl Sig for ast::ForeignItem {
 
                 Ok(extend_sig(ty_sig, text, defs, vec![]))
             }
-            ast::ForeignItemKind::TyAlias(..) => {
+            hir::ForeignItemKind::Type => {
                 let mut text = "type ".to_owned();
                 let name = self.ident.to_string();
                 let defs = vec![SigElement {
-                    id: id_from_node_id(self.id, scx),
+                    id: id_from_hir_id(self.hir_id, scx),
                     start: offset + text.len(),
                     end: offset + text.len() + name.len(),
                 }];
@@ -794,7 +813,6 @@ impl Sig for ast::ForeignItem {
 
                 Ok(Signature { text, defs, refs: vec![] })
             }
-            ast::ForeignItemKind::MacCall(..) => Err("macro"),
         }
     }
 }
@@ -802,14 +820,14 @@ impl Sig for ast::ForeignItem {
 fn name_and_generics(
     mut text: String,
     offset: usize,
-    generics: &ast::Generics,
-    id: NodeId,
+    generics: &hir::Generics<'_>,
+    id: hir::HirId,
     name: Ident,
     scx: &SaveContext<'_, '_>,
 ) -> Result {
     let name = name.to_string();
     let def = SigElement {
-        id: id_from_node_id(id, scx),
+        id: id_from_hir_id(id, scx),
         start: offset + text.len(),
         end: offset + text.len() + name.len(),
     };
@@ -821,16 +839,16 @@ fn name_and_generics(
 }
 
 fn make_assoc_type_signature(
-    id: NodeId,
+    id: hir::HirId,
     ident: Ident,
-    bounds: Option<&ast::GenericBounds>,
-    default: Option<&ast::Ty>,
+    bounds: Option<hir::GenericBounds<'_>>,
+    default: Option<&hir::Ty<'_>>,
     scx: &SaveContext<'_, '_>,
 ) -> Result {
     let mut text = "type ".to_owned();
     let name = ident.to_string();
     let mut defs = vec![SigElement {
-        id: id_from_node_id(id, scx),
+        id: id_from_hir_id(id, scx),
         start: text.len(),
         end: text.len() + name.len(),
     }];
@@ -839,7 +857,7 @@ fn make_assoc_type_signature(
     if let Some(bounds) = bounds {
         text.push_str(": ");
         // FIXME should descend into bounds
-        text.push_str(&pprust::bounds_to_string(bounds));
+        text.push_str(&bounds_to_string(bounds));
     }
     if let Some(default) = default {
         text.push_str(" = ");
@@ -853,16 +871,16 @@ fn make_assoc_type_signature(
 }
 
 fn make_assoc_const_signature(
-    id: NodeId,
+    id: hir::HirId,
     ident: Symbol,
-    ty: &ast::Ty,
-    default: Option<&ast::Expr>,
+    ty: &hir::Ty<'_>,
+    default: Option<&hir::Expr<'_>>,
     scx: &SaveContext<'_, '_>,
 ) -> Result {
     let mut text = "const ".to_owned();
     let name = ident.to_string();
     let mut defs = vec![SigElement {
-        id: id_from_node_id(id, scx),
+        id: id_from_hir_id(id, scx),
         start: text.len(),
         end: text.len() + name.len(),
     }];
@@ -877,41 +895,38 @@ fn make_assoc_const_signature(
 
     if let Some(default) = default {
         text.push_str(" = ");
-        text.push_str(&pprust::expr_to_string(default));
+        text.push_str(&id_to_string(&scx.tcx.hir(), default.hir_id));
     }
     text.push(';');
     Ok(Signature { text, defs, refs })
 }
 
 fn make_method_signature(
-    id: NodeId,
+    id: hir::HirId,
     ident: Ident,
-    generics: &ast::Generics,
-    m: &ast::FnSig,
+    generics: &hir::Generics<'_>,
+    m: &hir::FnSig<'_>,
     scx: &SaveContext<'_, '_>,
 ) -> Result {
     // FIXME code dup with function signature
     let mut text = String::new();
-    if let ast::Const::Yes(_) = m.header.constness {
+    if let hir::Constness::Const = m.header.constness {
         text.push_str("const ");
     }
-    if m.header.asyncness.is_async() {
+    if hir::IsAsync::Async == m.header.asyncness {
         text.push_str("async ");
     }
-    if let ast::Unsafe::Yes(_) = m.header.unsafety {
+    if let hir::Unsafety::Unsafe = m.header.unsafety {
         text.push_str("unsafe ");
     }
-    push_extern(&mut text, m.header.ext);
     text.push_str("fn ");
 
     let mut sig = name_and_generics(text, 0, generics, id, ident, scx)?;
 
     sig.text.push('(');
-    for i in &m.decl.inputs {
-        // FIXME should descend into patterns to add defs.
-        sig.text.push_str(&pprust::pat_to_string(&i.pat));
+    for i in m.decl.inputs {
         sig.text.push_str(": ");
-        let nested = i.ty.make(sig.text.len(), Some(i.id), scx)?;
+        let nested = i.make(sig.text.len(), Some(i.hir_id), scx)?;
         sig.text.push_str(&nested.text);
         sig.text.push(',');
         sig.defs.extend(nested.defs.into_iter());
@@ -919,7 +934,7 @@ fn make_method_signature(
     }
     sig.text.push(')');
 
-    if let ast::FnRetTy::Ty(ref t) = m.decl.output {
+    if let hir::FnRetTy::Return(ref t) = m.decl.output {
         sig.text.push_str(" -> ");
         let nested = t.make(sig.text.len(), None, scx)?;
         sig.text.push_str(&nested.text);
diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs
index c7d2205eb1c..fbab99b2f8f 100644
--- a/src/librustc_span/lib.rs
+++ b/src/librustc_span/lib.rs
@@ -25,6 +25,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 mod caching_source_map_view;
 pub mod source_map;
 pub use self::caching_source_map_view::CachingSourceMapView;
+use source_map::SourceMap;
 
 pub mod edition;
 use edition::Edition;
@@ -67,6 +68,7 @@ pub struct Globals {
     symbol_interner: Lock<symbol::Interner>,
     span_interner: Lock<span_encoding::SpanInterner>,
     hygiene_data: Lock<hygiene::HygieneData>,
+    source_map: Lock<Option<Lrc<SourceMap>>>,
 }
 
 impl Globals {
@@ -75,6 +77,7 @@ impl Globals {
             symbol_interner: Lock::new(symbol::Interner::fresh()),
             span_interner: Lock::new(span_encoding::SpanInterner::default()),
             hygiene_data: Lock::new(hygiene::HygieneData::new(edition)),
+            source_map: Lock::new(None),
         }
     }
 }
@@ -697,12 +700,44 @@ impl rustc_serialize::UseSpecializedDecodable for Span {
     }
 }
 
+/// Calls the provided closure, using the provided `SourceMap` to format
+/// any spans that are debug-printed during the closure'e exectuino.
+///
+/// Normally, the global `TyCtxt` is used to retrieve the `SourceMap`
+/// (see `rustc_interface::callbacks::span_debug1). However, some parts
+/// of the compiler (e.g. `rustc_parse`) may debug-print `Span`s before
+/// a `TyCtxt` is available. In this case, we fall back to
+/// the `SourceMap` provided to this function. If that is not available,
+/// we fall back to printing the raw `Span` field values
+pub fn with_source_map<T, F: FnOnce() -> T>(source_map: Lrc<SourceMap>, f: F) -> T {
+    GLOBALS.with(|globals| {
+        *globals.source_map.borrow_mut() = Some(source_map);
+    });
+    struct ClearSourceMap;
+    impl Drop for ClearSourceMap {
+        fn drop(&mut self) {
+            GLOBALS.with(|globals| {
+                globals.source_map.borrow_mut().take();
+            });
+        }
+    }
+
+    let _guard = ClearSourceMap;
+    f()
+}
+
 pub fn default_span_debug(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    f.debug_struct("Span")
-        .field("lo", &span.lo())
-        .field("hi", &span.hi())
-        .field("ctxt", &span.ctxt())
-        .finish()
+    GLOBALS.with(|globals| {
+        if let Some(source_map) = &*globals.source_map.borrow() {
+            write!(f, "{}", source_map.span_to_string(span))
+        } else {
+            f.debug_struct("Span")
+                .field("lo", &span.lo())
+                .field("hi", &span.hi())
+                .field("ctxt", &span.ctxt())
+                .finish()
+        }
+    })
 }
 
 impl fmt::Debug for Span {
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index c9558879a1c..f329c8c06cc 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -733,8 +733,7 @@ pub struct TargetOptions {
     pub lld_flavor: LldFlavor,
 
     /// Linker arguments that are passed *before* any user-defined libraries.
-    pub pre_link_args: LinkArgs, // ... unconditionally
-    pub pre_link_args_crt: LinkArgs, // ... when linking with a bundled crt
+    pub pre_link_args: LinkArgs,
     /// Objects to link before and after all other object code.
     pub pre_link_objects: CrtObjects,
     pub post_link_objects: CrtObjects,
@@ -997,7 +996,6 @@ impl Default for TargetOptions {
             linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.to_string()),
             lld_flavor: LldFlavor::Ld,
             pre_link_args: LinkArgs::new(),
-            pre_link_args_crt: LinkArgs::new(),
             post_link_args: LinkArgs::new(),
             link_script: None,
             asm_args: Vec::new(),
@@ -1397,7 +1395,6 @@ impl Target {
         key!(post_link_objects_fallback, link_objects);
         key!(crt_objects_fallback, crt_objects_fallback)?;
         key!(pre_link_args, link_args);
-        key!(pre_link_args_crt, link_args);
         key!(late_link_args, link_args);
         key!(late_link_args_dynamic, link_args);
         key!(late_link_args_static, link_args);
@@ -1629,7 +1626,6 @@ impl ToJson for Target {
         target_option_val!(post_link_objects_fallback);
         target_option_val!(crt_objects_fallback);
         target_option_val!(link_args - pre_link_args);
-        target_option_val!(link_args - pre_link_args_crt);
         target_option_val!(link_args - late_link_args);
         target_option_val!(link_args - late_link_args_dynamic);
         target_option_val!(link_args - late_link_args_static);
diff --git a/src/librustc_target/spec/tests/tests_impl.rs b/src/librustc_target/spec/tests/tests_impl.rs
index 4cf186bdd7c..788d1d2c484 100644
--- a/src/librustc_target/spec/tests/tests_impl.rs
+++ b/src/librustc_target/spec/tests/tests_impl.rs
@@ -25,7 +25,6 @@ impl Target {
         );
         for args in &[
             &self.options.pre_link_args,
-            &self.options.pre_link_args_crt,
             &self.options.late_link_args,
             &self.options.late_link_args_dynamic,
             &self.options.late_link_args_static,
diff --git a/src/librustc_target/spec/vxworks_base.rs b/src/librustc_target/spec/vxworks_base.rs
index 1b25c51278d..777bb58d7db 100644
--- a/src/librustc_target/spec/vxworks_base.rs
+++ b/src/librustc_target/spec/vxworks_base.rs
@@ -1,8 +1,6 @@
 use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
 
 pub fn opts() -> TargetOptions {
-    let mut args_crt = LinkArgs::new();
-    args_crt.insert(LinkerFlavor::Gcc, vec!["--static-crt".to_string()]);
     let mut args = LinkArgs::new();
     args.insert(
         LinkerFlavor::Gcc,
@@ -29,7 +27,6 @@ pub fn opts() -> TargetOptions {
         pre_link_args: args,
         position_independent_executables: false,
         has_elf_tls: true,
-        pre_link_args_crt: args_crt,
         crt_static_default: true,
         crt_static_respected: true,
         crt_static_allows_dylibs: true,
diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs
index f78a6207a3a..19caf64c63f 100644
--- a/src/librustc_trait_selection/opaque_types.rs
+++ b/src/librustc_trait_selection/opaque_types.rs
@@ -1253,9 +1253,6 @@ pub fn may_define_opaque_type(
 ///
 /// Requires that trait definitions have been processed so that we can
 /// elaborate predicates and walk supertraits.
-//
-// FIXME: callers may only have a `&[Predicate]`, not a `Vec`, so that's
-// what this code should accept.
 crate fn required_region_bounds(
     tcx: TyCtxt<'tcx>,
     erased_self_ty: Ty<'tcx>,
diff --git a/src/test/ui/derived-errors/issue-31997-1.stderr b/src/test/ui/derived-errors/issue-31997-1.stderr
index 6df748122a2..a4daf86cc8a 100644
--- a/src/test/ui/derived-errors/issue-31997-1.stderr
+++ b/src/test/ui/derived-errors/issue-31997-1.stderr
@@ -2,7 +2,14 @@ error[E0433]: failed to resolve: use of undeclared type or module `HashMap`
   --> $DIR/issue-31997-1.rs:20:19
    |
 LL |     let mut map = HashMap::new();
-   |                   ^^^^^^^ use of undeclared type or module `HashMap`
+   |                   ^^^^^^^ not found in this scope
+   |
+help: consider importing one of these items
+   |
+LL | use std::collections::HashMap;
+   |
+LL | use std::collections::hash_map::HashMap;
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0433.rs b/src/test/ui/error-codes/E0433.rs
index 9b54ec8c5cf..d555e654263 100644
--- a/src/test/ui/error-codes/E0433.rs
+++ b/src/test/ui/error-codes/E0433.rs
@@ -1,3 +1,3 @@
 fn main () {
-    let map = HashMap::new(); //~ ERROR E0433
+    let map = NonExistingMap::new(); //~ ERROR E0433
 }
diff --git a/src/test/ui/error-codes/E0433.stderr b/src/test/ui/error-codes/E0433.stderr
index d852e188384..d9555e1fcf7 100644
--- a/src/test/ui/error-codes/E0433.stderr
+++ b/src/test/ui/error-codes/E0433.stderr
@@ -1,8 +1,8 @@
-error[E0433]: failed to resolve: use of undeclared type or module `HashMap`
+error[E0433]: failed to resolve: use of undeclared type or module `NonExistingMap`
   --> $DIR/E0433.rs:2:15
    |
-LL |     let map = HashMap::new();
-   |               ^^^^^^^ use of undeclared type or module `HashMap`
+LL |     let map = NonExistingMap::new();
+   |               ^^^^^^^^^^^^^^ use of undeclared type or module `NonExistingMap`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr
index 986671c7810..c0539434d02 100644
--- a/src/test/ui/hygiene/no_implicit_prelude.stderr
+++ b/src/test/ui/hygiene/no_implicit_prelude.stderr
@@ -13,9 +13,15 @@ LL |     fn f() { ::bar::m!(); }
    |              ------------ in this macro invocation
 ...
 LL |         Vec::new();
-   |         ^^^ use of undeclared type or module `Vec`
+   |         ^^^ not found in this scope
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider importing one of these items
+   |
+LL |     use std::prelude::v1::Vec;
+   |
+LL |     use std::vec::Vec;
+   |
 
 error[E0599]: no method named `clone` found for unit type `()` in the current scope
   --> $DIR/no_implicit_prelude.rs:12:12
diff --git a/src/test/ui/issues/issue-72554.rs b/src/test/ui/issues/issue-72554.rs
new file mode 100644
index 00000000000..47aca05d778
--- /dev/null
+++ b/src/test/ui/issues/issue-72554.rs
@@ -0,0 +1,20 @@
+use std::collections::BTreeSet;
+
+#[derive(Hash)]
+pub enum ElemDerived { //~ ERROR recursive type `ElemDerived` has infinite size
+    A(ElemDerived)
+}
+
+pub enum Elem {
+    Derived(ElemDerived)
+}
+
+pub struct Set(BTreeSet<Elem>);
+
+impl Set {
+    pub fn into_iter(self) -> impl Iterator<Item = Elem> {
+        self.0.into_iter()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-72554.stderr b/src/test/ui/issues/issue-72554.stderr
new file mode 100644
index 00000000000..9db65f4a2ee
--- /dev/null
+++ b/src/test/ui/issues/issue-72554.stderr
@@ -0,0 +1,13 @@
+error[E0072]: recursive type `ElemDerived` has infinite size
+  --> $DIR/issue-72554.rs:4:1
+   |
+LL | pub enum ElemDerived {
+   | ^^^^^^^^^^^^^^^^^^^^ recursive type has infinite size
+LL |     A(ElemDerived)
+   |       ----------- recursive without indirection
+   |
+   = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ElemDerived` representable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0072`.
diff --git a/src/test/ui/resolve/use_suggestion.rs b/src/test/ui/resolve/use_suggestion.rs
new file mode 100644
index 00000000000..8c9bc6d76b8
--- /dev/null
+++ b/src/test/ui/resolve/use_suggestion.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let x1 = HashMap::new(); //~ ERROR failed to resolve
+    let x2 = GooMap::new(); //~ ERROR failed to resolve
+
+    let y1: HashMap; //~ ERROR cannot find type
+    let y2: GooMap; //~ ERROR cannot find type
+}
diff --git a/src/test/ui/resolve/use_suggestion.stderr b/src/test/ui/resolve/use_suggestion.stderr
new file mode 100644
index 00000000000..2fd3d5dccd2
--- /dev/null
+++ b/src/test/ui/resolve/use_suggestion.stderr
@@ -0,0 +1,42 @@
+error[E0433]: failed to resolve: use of undeclared type or module `GooMap`
+  --> $DIR/use_suggestion.rs:3:14
+   |
+LL |     let x2 = GooMap::new();
+   |              ^^^^^^ use of undeclared type or module `GooMap`
+
+error[E0433]: failed to resolve: use of undeclared type or module `HashMap`
+  --> $DIR/use_suggestion.rs:2:14
+   |
+LL |     let x1 = HashMap::new();
+   |              ^^^^^^^ not found in this scope
+   |
+help: consider importing one of these items
+   |
+LL | use std::collections::HashMap;
+   |
+LL | use std::collections::hash_map::HashMap;
+   |
+
+error[E0412]: cannot find type `HashMap` in this scope
+  --> $DIR/use_suggestion.rs:5:13
+   |
+LL |     let y1: HashMap;
+   |             ^^^^^^^ not found in this scope
+   |
+help: consider importing one of these items
+   |
+LL | use std::collections::HashMap;
+   |
+LL | use std::collections::hash_map::HashMap;
+   |
+
+error[E0412]: cannot find type `GooMap` in this scope
+  --> $DIR/use_suggestion.rs:6:13
+   |
+LL |     let y2: GooMap;
+   |             ^^^^^^ not found in this scope
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0412, E0433.
+For more information about an error, try `rustc --explain E0412`.
diff --git a/src/tools/rls b/src/tools/rls
-Subproject 085f24b9ecbc0e90d204cab1c111c4abe4608ce
+Subproject 8d7a7167c15b9154755588c39b22b2336c89ca6