about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-01-28 09:01:33 +0000
committerbors <bors@rust-lang.org>2021-01-28 09:01:33 +0000
commit0e190206e2ff0c13d64701d9b4145bf89a2d0cab (patch)
treef081fe04717328752fade190520b7c3b1579565b
parente32f372c4203b2527221b313cf63b05ea178e8a9 (diff)
parentf3dfbfc8f5f2b17c7f6fe12b4ba48f589d54dc87 (diff)
downloadrust-0e190206e2ff0c13d64701d9b4145bf89a2d0cab.tar.gz
rust-0e190206e2ff0c13d64701d9b4145bf89a2d0cab.zip
Auto merge of #81461 - JohnTitor:rollup-b0ij25f, r=JohnTitor
Rollup of 13 pull requests

Successful merges:

 - #70904 (Stabilize `Seek::stream_position` (feature `seek_convenience`))
 - #79951 (Refractor a few more types to `rustc_type_ir` )
 - #80868 (Print failure message on all tests that should panic, but don't)
 - #81062 (Improve diagnostics for Precise Capture)
 - #81277 (Make more traits of the From/Into family diagnostic items)
 - #81284 (Make `-Z time-passes` less noisy)
 - #81379 (Improve URLs handling)
 - #81416 (Tweak suggestion for missing field in patterns)
 - #81426 (const_evaluatable: expand abstract consts in try_unify)
 - #81428 (compiletest: Add two more unit tests)
 - #81430 (add const_evaluatable_checked test)
 - #81433 (const_evaluatable: stop looking into type aliases)
 - #81445 (Update cargo)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock11
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs35
-rw-r--r--compiler/rustc_codegen_llvm/src/type_.rs37
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs20
-rw-r--r--compiler/rustc_expand/src/base.rs6
-rw-r--r--compiler/rustc_expand/src/expand.rs2
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs3
-rw-r--r--compiler/rustc_interface/src/passes.rs17
-rw-r--r--compiler/rustc_lint/src/types.rs60
-rw-r--r--compiler/rustc_middle/src/infer/unify_key.rs53
-rw-r--r--compiler/rustc_middle/src/ty/cast.rs3
-rw-r--r--compiler/rustc_middle/src/ty/context.rs70
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs3
-rw-r--r--compiler/rustc_middle/src/ty/error.rs3
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs7
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs45
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs157
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs33
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs59
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs74
-rw-r--r--compiler/rustc_middle/src/ty/util.rs14
-rw-r--r--compiler/rustc_mir/src/interpret/cast.rs12
-rw-r--r--compiler/rustc_mir/src/interpret/operator.rs3
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs5
-rw-r--r--compiler/rustc_mir_build/src/thir/constant.rs8
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs11
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs8
-rw-r--r--compiler/rustc_passes/src/intrinsicck.rs4
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs26
-rw-r--r--compiler/rustc_traits/src/chalk/db.rs28
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs58
-rw-r--r--compiler/rustc_type_ir/Cargo.toml1
-rw-r--r--compiler/rustc_type_ir/src/lib.rs406
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs6
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs3
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs14
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs29
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs25
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs149
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs2
-rw-r--r--compiler/rustc_typeck/src/coherence/inherent_impls.rs29
-rw-r--r--compiler/rustc_typeck/src/collect.rs34
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs2
-rw-r--r--library/core/src/convert/mod.rs3
-rw-r--r--library/std/src/io/buffered/bufreader.rs1
-rw-r--r--library/std/src/io/mod.rs7
-rw-r--r--library/test/src/test_result.rs2
-rw-r--r--library/test/src/tests.rs39
-rw-r--r--src/librustdoc/clean/types.rs39
-rw-r--r--src/librustdoc/clean/utils.rs16
-rw-r--r--src/librustdoc/html/static/main.js24
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs18
-rw-r--r--src/test/ui/closures/2229_closure_analysis/capture-analysis-1.rs35
-rw-r--r--src/test/ui/closures/2229_closure_analysis/capture-analysis-1.stderr77
-rw-r--r--src/test/ui/closures/2229_closure_analysis/capture-analysis-2.rs30
-rw-r--r--src/test/ui/closures/2229_closure_analysis/capture-analysis-2.stderr65
-rw-r--r--src/test/ui/closures/2229_closure_analysis/capture-analysis-3.rs35
-rw-r--r--src/test/ui/closures/2229_closure_analysis/capture-analysis-3.stderr65
-rw-r--r--src/test/ui/closures/2229_closure_analysis/capture-analysis-4.rs33
-rw-r--r--src/test/ui/closures/2229_closure_analysis/capture-analysis-4.stderr62
-rw-r--r--src/test/ui/closures/2229_closure_analysis/deep-multilevel-struct.rs52
-rw-r--r--src/test/ui/closures/2229_closure_analysis/deep-multilevel-struct.stderr70
-rw-r--r--src/test/ui/closures/2229_closure_analysis/deep-multilevel-tuple.rs27
-rw-r--r--src/test/ui/closures/2229_closure_analysis/deep-multilevel-tuple.stderr70
-rw-r--r--src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.rs4
-rw-r--r--src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.stderr5
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/elaborate-trait-pred.rs24
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/nested-abstract-consts-1.rs24
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/nested-abstract-consts-2.rs35
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-1.rs35
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-2.rs29
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr8
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr11
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs6
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/ty-alias-substitution.rs14
-rw-r--r--src/test/ui/destructuring-assignment/struct_destructure_fail.stderr8
-rw-r--r--src/test/ui/error-codes/E0027.stderr12
-rw-r--r--src/test/ui/structs/struct-pat-derived-error.stderr4
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/bytecount.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/consts.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_clike.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/fallible_impl_from.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/float_literal.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/mutex_atomic.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/types.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/mod.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/paths.rs1
-rw-r--r--src/tools/compiletest/src/common.rs2
-rw-r--r--src/tools/compiletest/src/util/tests.rs19
95 files changed, 1927 insertions, 732 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9d726b240da..fb5ae6ce663 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -770,7 +770,7 @@ checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
 
 [[package]]
 name = "crates-io"
-version = "0.31.1"
+version = "0.33.0"
 dependencies = [
  "anyhow",
  "curl",
@@ -1337,9 +1337,9 @@ dependencies = [
 
 [[package]]
 name = "git2"
-version = "0.13.14"
+version = "0.13.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "186dd99cc77576e58344ad614fa9bb27bad9d048f85de3ca850c1f4e8b048260"
+checksum = "1d250f5f82326884bd39c2853577e70a121775db76818ffa452ed1e80de12986"
 dependencies = [
  "bitflags",
  "libc",
@@ -1792,9 +1792,9 @@ dependencies = [
 
 [[package]]
 name = "libgit2-sys"
-version = "0.12.16+1.1.0"
+version = "0.12.18+1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f91b2f931ee975a98155195be8cd82d02e8e029d7d793d2bac1b8181ac97020"
+checksum = "3da6a42da88fc37ee1ecda212ffa254c25713532980005d5f7c0b0fbe7e6e885"
 dependencies = [
  "cc",
  "libc",
@@ -4345,6 +4345,7 @@ dependencies = [
  "bitflags",
  "rustc_data_structures",
  "rustc_index",
+ "rustc_macros",
  "rustc_serialize",
 ]
 
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 6e4f3bf2898..f31c58b92e4 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -83,7 +83,6 @@ mod vtable;
 mod prelude {
     pub(crate) use std::convert::{TryFrom, TryInto};
 
-    pub(crate) use rustc_ast::ast::{FloatTy, IntTy, UintTy};
     pub(crate) use rustc_span::Span;
 
     pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
@@ -91,7 +90,7 @@ mod prelude {
     pub(crate) use rustc_middle::mir::{self, *};
     pub(crate) use rustc_middle::ty::layout::{self, TyAndLayout};
     pub(crate) use rustc_middle::ty::{
-        self, FnSig, Instance, InstanceDef, ParamEnv, Ty, TyCtxt, TypeAndMut, TypeFoldable,
+        self, FloatTy, FnSig, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut, TypeFoldable, UintTy,
     };
     pub(crate) use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx};
 
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index f122fa14e70..d2f4d3edc22 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -304,9 +304,8 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         lhs: Self::Value,
         rhs: Self::Value,
     ) -> (Self::Value, Self::Value) {
-        use rustc_ast::IntTy::*;
-        use rustc_ast::UintTy::*;
         use rustc_middle::ty::{Int, Uint};
+        use rustc_middle::ty::{IntTy::*, UintTy::*};
 
         let new_kind = match ty.kind() {
             Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)),
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index b9ae7963250..3a4e1492af3 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -18,7 +18,6 @@ use crate::llvm::debuginfo::{
 };
 use crate::value::Value;
 
-use rustc_ast as ast;
 use rustc_codegen_ssa::traits::*;
 use rustc_data_structures::const_cstr;
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -830,37 +829,37 @@ trait MsvcBasicName {
     fn msvc_basic_name(self) -> &'static str;
 }
 
-impl MsvcBasicName for ast::IntTy {
+impl MsvcBasicName for ty::IntTy {
     fn msvc_basic_name(self) -> &'static str {
         match self {
-            ast::IntTy::Isize => "ptrdiff_t",
-            ast::IntTy::I8 => "__int8",
-            ast::IntTy::I16 => "__int16",
-            ast::IntTy::I32 => "__int32",
-            ast::IntTy::I64 => "__int64",
-            ast::IntTy::I128 => "__int128",
+            ty::IntTy::Isize => "ptrdiff_t",
+            ty::IntTy::I8 => "__int8",
+            ty::IntTy::I16 => "__int16",
+            ty::IntTy::I32 => "__int32",
+            ty::IntTy::I64 => "__int64",
+            ty::IntTy::I128 => "__int128",
         }
     }
 }
 
-impl MsvcBasicName for ast::UintTy {
+impl MsvcBasicName for ty::UintTy {
     fn msvc_basic_name(self) -> &'static str {
         match self {
-            ast::UintTy::Usize => "size_t",
-            ast::UintTy::U8 => "unsigned __int8",
-            ast::UintTy::U16 => "unsigned __int16",
-            ast::UintTy::U32 => "unsigned __int32",
-            ast::UintTy::U64 => "unsigned __int64",
-            ast::UintTy::U128 => "unsigned __int128",
+            ty::UintTy::Usize => "size_t",
+            ty::UintTy::U8 => "unsigned __int8",
+            ty::UintTy::U16 => "unsigned __int16",
+            ty::UintTy::U32 => "unsigned __int32",
+            ty::UintTy::U64 => "unsigned __int64",
+            ty::UintTy::U128 => "unsigned __int128",
         }
     }
 }
 
-impl MsvcBasicName for ast::FloatTy {
+impl MsvcBasicName for ty::FloatTy {
     fn msvc_basic_name(self) -> &'static str {
         match self {
-            ast::FloatTy::F32 => "float",
-            ast::FloatTy::F64 => "double",
+            ty::FloatTy::F32 => "float",
+            ty::FloatTy::F64 => "double",
         }
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index a43724fd495..8fd0caae479 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -7,13 +7,12 @@ use crate::llvm;
 use crate::llvm::{Bool, False, True};
 use crate::type_of::LayoutLlvmExt;
 use crate::value::Value;
-use rustc_ast as ast;
 use rustc_codegen_ssa::common::TypeKind;
 use rustc_codegen_ssa::traits::*;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_middle::bug;
 use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{self, Ty};
 use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
 use rustc_target::abi::{AddressSpace, Align, Integer, Size};
 
@@ -80,32 +79,32 @@ impl CodegenCx<'ll, 'tcx> {
         self.type_i8()
     }
 
-    crate fn type_int_from_ty(&self, t: ast::IntTy) -> &'ll Type {
+    crate fn type_int_from_ty(&self, t: ty::IntTy) -> &'ll Type {
         match t {
-            ast::IntTy::Isize => self.type_isize(),
-            ast::IntTy::I8 => self.type_i8(),
-            ast::IntTy::I16 => self.type_i16(),
-            ast::IntTy::I32 => self.type_i32(),
-            ast::IntTy::I64 => self.type_i64(),
-            ast::IntTy::I128 => self.type_i128(),
+            ty::IntTy::Isize => self.type_isize(),
+            ty::IntTy::I8 => self.type_i8(),
+            ty::IntTy::I16 => self.type_i16(),
+            ty::IntTy::I32 => self.type_i32(),
+            ty::IntTy::I64 => self.type_i64(),
+            ty::IntTy::I128 => self.type_i128(),
         }
     }
 
-    crate fn type_uint_from_ty(&self, t: ast::UintTy) -> &'ll Type {
+    crate fn type_uint_from_ty(&self, t: ty::UintTy) -> &'ll Type {
         match t {
-            ast::UintTy::Usize => self.type_isize(),
-            ast::UintTy::U8 => self.type_i8(),
-            ast::UintTy::U16 => self.type_i16(),
-            ast::UintTy::U32 => self.type_i32(),
-            ast::UintTy::U64 => self.type_i64(),
-            ast::UintTy::U128 => self.type_i128(),
+            ty::UintTy::Usize => self.type_isize(),
+            ty::UintTy::U8 => self.type_i8(),
+            ty::UintTy::U16 => self.type_i16(),
+            ty::UintTy::U32 => self.type_i32(),
+            ty::UintTy::U64 => self.type_i64(),
+            ty::UintTy::U128 => self.type_i128(),
         }
     }
 
-    crate fn type_float_from_ty(&self, t: ast::FloatTy) -> &'ll Type {
+    crate fn type_float_from_ty(&self, t: ty::FloatTy) -> &'ll Type {
         match t {
-            ast::FloatTy::F32 => self.type_f32(),
-            ast::FloatTy::F64 => self.type_f64(),
+            ty::FloatTy::F32 => self.type_f32(),
+            ty::FloatTy::F64 => self.type_f64(),
         }
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index ecac05fd955..c8219081678 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -875,20 +875,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             ty::Uint(_) => value.to_string(),
                             ty::Int(int_ty) => {
                                 match int_ty.normalize(bx.tcx().sess.target.pointer_width) {
-                                    ast::IntTy::I8 => (value as i8).to_string(),
-                                    ast::IntTy::I16 => (value as i16).to_string(),
-                                    ast::IntTy::I32 => (value as i32).to_string(),
-                                    ast::IntTy::I64 => (value as i64).to_string(),
-                                    ast::IntTy::I128 => (value as i128).to_string(),
-                                    ast::IntTy::Isize => unreachable!(),
+                                    ty::IntTy::I8 => (value as i8).to_string(),
+                                    ty::IntTy::I16 => (value as i16).to_string(),
+                                    ty::IntTy::I32 => (value as i32).to_string(),
+                                    ty::IntTy::I64 => (value as i64).to_string(),
+                                    ty::IntTy::I128 => (value as i128).to_string(),
+                                    ty::IntTy::Isize => unreachable!(),
                                 }
                             }
-                            ty::Float(ast::FloatTy::F32) => {
-                                f32::from_bits(value as u32).to_string()
-                            }
-                            ty::Float(ast::FloatTy::F64) => {
-                                f64::from_bits(value as u64).to_string()
-                            }
+                            ty::Float(ty::FloatTy::F32) => f32::from_bits(value as u32).to_string(),
+                            ty::Float(ty::FloatTy::F64) => f64::from_bits(value as u64).to_string(),
                             _ => span_bug!(span, "asm const has bad type {}", ty),
                         };
                         InlineAsmOperandRef::Const { string }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 2f43940a9dc..08543d1622a 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -929,7 +929,9 @@ pub struct ExtCtxt<'a> {
     pub force_mode: bool,
     pub expansions: FxHashMap<Span, Vec<String>>,
     /// Called directly after having parsed an external `mod foo;` in expansion.
-    pub(super) extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>,
+    ///
+    /// `Ident` is the module name.
+    pub(super) extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate, Ident)>,
 }
 
 impl<'a> ExtCtxt<'a> {
@@ -937,7 +939,7 @@ impl<'a> ExtCtxt<'a> {
         sess: &'a Session,
         ecfg: expand::ExpansionConfig<'a>,
         resolver: &'a mut dyn ResolverExpand,
-        extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>,
+        extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate, Ident)>,
     ) -> ExtCtxt<'a> {
         ExtCtxt {
             sess,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 5d398935ce8..50832d5edbf 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1407,7 +1407,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                         proc_macros: vec![],
                     };
                     if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded {
-                        extern_mod_loaded(&krate);
+                        extern_mod_loaded(&krate, ident);
                     }
 
                     *old_mod = krate.module;
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index b344086e95e..e034ac5e8fd 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -34,7 +34,6 @@ use super::{InferCtxt, MiscVariable, TypeTrace};
 
 use crate::traits::{Obligation, PredicateObligations};
 
-use rustc_ast as ast;
 use rustc_data_structures::sso::SsoHashMap;
 use rustc_hir::def_id::DefId;
 use rustc_middle::traits::ObligationCause;
@@ -281,7 +280,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
         &self,
         vid_is_expected: bool,
         vid: ty::FloatVid,
-        val: ast::FloatTy,
+        val: ty::FloatTy,
     ) -> RelateResult<'tcx, Ty<'tcx>> {
         self.inner
             .borrow_mut()
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 7031234e108..56aa3939b22 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -33,7 +33,7 @@ use rustc_session::lint;
 use rustc_session::output::{filename_for_input, filename_for_metadata};
 use rustc_session::search_paths::PathKind;
 use rustc_session::Session;
-use rustc_span::symbol::Symbol;
+use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{FileName, RealFileName};
 use rustc_trait_selection::traits;
 use rustc_typeck as typeck;
@@ -211,8 +211,13 @@ pub fn register_plugins<'a>(
     Ok((krate, lint_store))
 }
 
-fn pre_expansion_lint(sess: &Session, lint_store: &LintStore, krate: &ast::Crate) {
-    sess.time("pre_AST_expansion_lint_checks", || {
+fn pre_expansion_lint(
+    sess: &Session,
+    lint_store: &LintStore,
+    krate: &ast::Crate,
+    crate_name: &str,
+) {
+    sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", crate_name).run(|| {
         rustc_lint::check_ast_crate(
             sess,
             lint_store,
@@ -233,7 +238,7 @@ fn configure_and_expand_inner<'a>(
     metadata_loader: &'a MetadataLoaderDyn,
 ) -> Result<(ast::Crate, Resolver<'a>)> {
     tracing::trace!("configure_and_expand_inner");
-    pre_expansion_lint(sess, lint_store, &krate);
+    pre_expansion_lint(sess, lint_store, &krate, crate_name);
 
     let mut resolver = Resolver::new(sess, &krate, crate_name, metadata_loader, &resolver_arenas);
     rustc_builtin_macros::register_builtin_macros(&mut resolver);
@@ -295,7 +300,9 @@ fn configure_and_expand_inner<'a>(
             ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string())
         };
 
-        let extern_mod_loaded = |k: &ast::Crate| pre_expansion_lint(sess, lint_store, k);
+        let extern_mod_loaded = |k: &ast::Crate, ident: Ident| {
+            pre_expansion_lint(sess, lint_store, k, &*ident.name.as_str())
+        };
         let mut ecx = ExtCtxt::new(&sess, cfg, &mut resolver, Some(&extern_mod_loaded));
 
         // Expand macros now!
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 424f91b3f88..1e879d29370 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -168,25 +168,25 @@ fn lint_overflowing_range_endpoint<'tcx>(
 
 // For `isize` & `usize`, be conservative with the warnings, so that the
 // warnings are consistent between 32- and 64-bit platforms.
-fn int_ty_range(int_ty: ast::IntTy) -> (i128, i128) {
+fn int_ty_range(int_ty: ty::IntTy) -> (i128, i128) {
     match int_ty {
-        ast::IntTy::Isize => (i64::MIN.into(), i64::MAX.into()),
-        ast::IntTy::I8 => (i8::MIN.into(), i8::MAX.into()),
-        ast::IntTy::I16 => (i16::MIN.into(), i16::MAX.into()),
-        ast::IntTy::I32 => (i32::MIN.into(), i32::MAX.into()),
-        ast::IntTy::I64 => (i64::MIN.into(), i64::MAX.into()),
-        ast::IntTy::I128 => (i128::MIN, i128::MAX),
+        ty::IntTy::Isize => (i64::MIN.into(), i64::MAX.into()),
+        ty::IntTy::I8 => (i8::MIN.into(), i8::MAX.into()),
+        ty::IntTy::I16 => (i16::MIN.into(), i16::MAX.into()),
+        ty::IntTy::I32 => (i32::MIN.into(), i32::MAX.into()),
+        ty::IntTy::I64 => (i64::MIN.into(), i64::MAX.into()),
+        ty::IntTy::I128 => (i128::MIN, i128::MAX),
     }
 }
 
-fn uint_ty_range(uint_ty: ast::UintTy) -> (u128, u128) {
+fn uint_ty_range(uint_ty: ty::UintTy) -> (u128, u128) {
     let max = match uint_ty {
-        ast::UintTy::Usize => u64::MAX.into(),
-        ast::UintTy::U8 => u8::MAX.into(),
-        ast::UintTy::U16 => u16::MAX.into(),
-        ast::UintTy::U32 => u32::MAX.into(),
-        ast::UintTy::U64 => u64::MAX.into(),
-        ast::UintTy::U128 => u128::MAX,
+        ty::UintTy::Usize => u64::MAX.into(),
+        ty::UintTy::U8 => u8::MAX.into(),
+        ty::UintTy::U16 => u16::MAX.into(),
+        ty::UintTy::U32 => u32::MAX.into(),
+        ty::UintTy::U64 => u64::MAX.into(),
+        ty::UintTy::U128 => u128::MAX,
     };
     (0, max)
 }
@@ -258,8 +258,8 @@ fn report_bin_hex_error(
 //
 // No suggestion for: `isize`, `usize`.
 fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option<&'static str> {
-    use rustc_ast::IntTy::*;
-    use rustc_ast::UintTy::*;
+    use ty::IntTy::*;
+    use ty::UintTy::*;
     macro_rules! find_fit {
         ($ty:expr, $val:expr, $negative:expr,
          $($type:ident => [$($utypes:expr),*] => [$($itypes:expr),*]),+) => {
@@ -302,7 +302,7 @@ fn lint_int_literal<'tcx>(
     type_limits: &TypeLimits,
     e: &'tcx hir::Expr<'tcx>,
     lit: &hir::Lit,
-    t: ast::IntTy,
+    t: ty::IntTy,
     v: u128,
 ) {
     let int_type = t.normalize(cx.sess().target.pointer_width);
@@ -314,7 +314,14 @@ fn lint_int_literal<'tcx>(
     // avoiding use of -min to prevent overflow/panic
     if (negative && v > max + 1) || (!negative && v > max) {
         if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
-            report_bin_hex_error(cx, e, attr::IntType::SignedInt(t), repr_str, v, negative);
+            report_bin_hex_error(
+                cx,
+                e,
+                attr::IntType::SignedInt(ty::ast_int_ty(t)),
+                repr_str,
+                v,
+                negative,
+            );
             return;
         }
 
@@ -351,7 +358,7 @@ fn lint_uint_literal<'tcx>(
     cx: &LateContext<'tcx>,
     e: &'tcx hir::Expr<'tcx>,
     lit: &hir::Lit,
-    t: ast::UintTy,
+    t: ty::UintTy,
 ) {
     let uint_type = t.normalize(cx.sess().target.pointer_width);
     let (min, max) = uint_ty_range(uint_type);
@@ -391,7 +398,14 @@ fn lint_uint_literal<'tcx>(
             }
         }
         if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
-            report_bin_hex_error(cx, e, attr::IntType::UnsignedInt(t), repr_str, lit_val, false);
+            report_bin_hex_error(
+                cx,
+                e,
+                attr::IntType::UnsignedInt(ty::ast_uint_ty(t)),
+                repr_str,
+                lit_val,
+                false,
+            );
             return;
         }
         cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
@@ -430,8 +444,8 @@ fn lint_literal<'tcx>(
         ty::Float(t) => {
             let is_infinite = match lit.node {
                 ast::LitKind::Float(v, _) => match t {
-                    ast::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite),
-                    ast::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite),
+                    ty::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite),
+                    ty::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite),
                 },
                 _ => bug!(),
             };
@@ -984,7 +998,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 help: Some("consider using `u32` or `libc::wchar_t` instead".into()),
             },
 
-            ty::Int(ast::IntTy::I128) | ty::Uint(ast::UintTy::U128) => FfiUnsafe {
+            ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => FfiUnsafe {
                 ty,
                 reason: "128-bit integers don't currently have a known stable ABI".into(),
                 help: None,
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index 16e9aafb25a..8318bdefc8e 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -1,4 +1,4 @@
-use crate::ty::{self, FloatVarValue, InferConst, IntVarValue, Ty, TyCtxt};
+use crate::ty::{self, InferConst, Ty, TyCtxt};
 use rustc_data_structures::snapshot_vec;
 use rustc_data_structures::undo_log::UndoLogs;
 use rustc_data_structures::unify::{
@@ -15,36 +15,6 @@ pub trait ToType {
     fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
 }
 
-/// Raw `TyVid` are used as the unification key for `sub_relations`;
-/// they carry no values.
-impl UnifyKey for ty::TyVid {
-    type Value = ();
-    fn index(&self) -> u32 {
-        self.index
-    }
-    fn from_index(i: u32) -> ty::TyVid {
-        ty::TyVid { index: i }
-    }
-    fn tag() -> &'static str {
-        "TyVid"
-    }
-}
-
-impl UnifyKey for ty::IntVid {
-    type Value = Option<IntVarValue>;
-    fn index(&self) -> u32 {
-        self.index
-    }
-    fn from_index(i: u32) -> ty::IntVid {
-        ty::IntVid { index: i }
-    }
-    fn tag() -> &'static str {
-        "IntVid"
-    }
-}
-
-impl EqUnifyValue for IntVarValue {}
-
 #[derive(PartialEq, Copy, Clone, Debug)]
 pub struct RegionVidKey {
     /// The minimum region vid in the unification set. This is needed
@@ -80,7 +50,7 @@ impl UnifyKey for ty::RegionVid {
     }
 }
 
-impl ToType for IntVarValue {
+impl ToType for ty::IntVarValue {
     fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match *self {
             ty::IntType(i) => tcx.mk_mach_int(i),
@@ -89,24 +59,7 @@ impl ToType for IntVarValue {
     }
 }
 
-// Floating point type keys
-
-impl UnifyKey for ty::FloatVid {
-    type Value = Option<FloatVarValue>;
-    fn index(&self) -> u32 {
-        self.index
-    }
-    fn from_index(i: u32) -> ty::FloatVid {
-        ty::FloatVid { index: i }
-    }
-    fn tag() -> &'static str {
-        "FloatVid"
-    }
-}
-
-impl EqUnifyValue for FloatVarValue {}
-
-impl ToType for FloatVarValue {
+impl ToType for ty::FloatVarValue {
     fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         tcx.mk_mach_float(self.0)
     }
diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs
index d737d1ebf56..20a6af5f6c1 100644
--- a/compiler/rustc_middle/src/ty/cast.rs
+++ b/compiler/rustc_middle/src/ty/cast.rs
@@ -3,13 +3,12 @@
 
 use crate::ty::{self, Ty};
 
-use rustc_ast as ast;
 use rustc_macros::HashStable;
 
 /// Types that are represented as ints.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum IntTy {
-    U(ast::UintTy),
+    U(ty::UintTy),
     I,
     CEnum,
     Bool,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 1cbf761e6c7..1255302f743 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -19,10 +19,10 @@ use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, Substs
 use crate::ty::TyKind::*;
 use crate::ty::{
     self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid,
-    DefIdTree, ExistentialPredicate, FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy,
-    IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind,
-    ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar,
-    TyVid, TypeAndMut, Visibility,
+    DefIdTree, ExistentialPredicate, FloatTy, FloatVar, FloatVid, GenericParamDefKind, InferConst,
+    InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate,
+    PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions,
+    TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
 };
 use rustc_ast as ast;
 use rustc_ast::expand::allocator::AllocatorKind;
@@ -839,20 +839,20 @@ impl<'tcx> CommonTypes<'tcx> {
             bool: mk(Bool),
             char: mk(Char),
             never: mk(Never),
-            isize: mk(Int(ast::IntTy::Isize)),
-            i8: mk(Int(ast::IntTy::I8)),
-            i16: mk(Int(ast::IntTy::I16)),
-            i32: mk(Int(ast::IntTy::I32)),
-            i64: mk(Int(ast::IntTy::I64)),
-            i128: mk(Int(ast::IntTy::I128)),
-            usize: mk(Uint(ast::UintTy::Usize)),
-            u8: mk(Uint(ast::UintTy::U8)),
-            u16: mk(Uint(ast::UintTy::U16)),
-            u32: mk(Uint(ast::UintTy::U32)),
-            u64: mk(Uint(ast::UintTy::U64)),
-            u128: mk(Uint(ast::UintTy::U128)),
-            f32: mk(Float(ast::FloatTy::F32)),
-            f64: mk(Float(ast::FloatTy::F64)),
+            isize: mk(Int(ty::IntTy::Isize)),
+            i8: mk(Int(ty::IntTy::I8)),
+            i16: mk(Int(ty::IntTy::I16)),
+            i32: mk(Int(ty::IntTy::I32)),
+            i64: mk(Int(ty::IntTy::I64)),
+            i128: mk(Int(ty::IntTy::I128)),
+            usize: mk(Uint(ty::UintTy::Usize)),
+            u8: mk(Uint(ty::UintTy::U8)),
+            u16: mk(Uint(ty::UintTy::U16)),
+            u32: mk(Uint(ty::UintTy::U32)),
+            u64: mk(Uint(ty::UintTy::U64)),
+            u128: mk(Uint(ty::UintTy::U128)),
+            f32: mk(Float(ty::FloatTy::F32)),
+            f64: mk(Float(ty::FloatTy::F64)),
             str_: mk(Str),
             self_param: mk(ty::Param(ty::ParamTy { index: 0, name: kw::SelfUpper })),
 
@@ -2102,32 +2102,32 @@ impl<'tcx> TyCtxt<'tcx> {
         if pred.kind() != binder { self.mk_predicate(binder) } else { pred }
     }
 
-    pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> {
+    pub fn mk_mach_int(self, tm: IntTy) -> Ty<'tcx> {
         match tm {
-            ast::IntTy::Isize => self.types.isize,
-            ast::IntTy::I8 => self.types.i8,
-            ast::IntTy::I16 => self.types.i16,
-            ast::IntTy::I32 => self.types.i32,
-            ast::IntTy::I64 => self.types.i64,
-            ast::IntTy::I128 => self.types.i128,
+            IntTy::Isize => self.types.isize,
+            IntTy::I8 => self.types.i8,
+            IntTy::I16 => self.types.i16,
+            IntTy::I32 => self.types.i32,
+            IntTy::I64 => self.types.i64,
+            IntTy::I128 => self.types.i128,
         }
     }
 
-    pub fn mk_mach_uint(self, tm: ast::UintTy) -> Ty<'tcx> {
+    pub fn mk_mach_uint(self, tm: UintTy) -> Ty<'tcx> {
         match tm {
-            ast::UintTy::Usize => self.types.usize,
-            ast::UintTy::U8 => self.types.u8,
-            ast::UintTy::U16 => self.types.u16,
-            ast::UintTy::U32 => self.types.u32,
-            ast::UintTy::U64 => self.types.u64,
-            ast::UintTy::U128 => self.types.u128,
+            UintTy::Usize => self.types.usize,
+            UintTy::U8 => self.types.u8,
+            UintTy::U16 => self.types.u16,
+            UintTy::U32 => self.types.u32,
+            UintTy::U64 => self.types.u64,
+            UintTy::U128 => self.types.u128,
         }
     }
 
-    pub fn mk_mach_float(self, tm: ast::FloatTy) -> Ty<'tcx> {
+    pub fn mk_mach_float(self, tm: FloatTy) -> Ty<'tcx> {
         match tm {
-            ast::FloatTy::F32 => self.types.f32,
-            ast::FloatTy::F64 => self.types.f64,
+            FloatTy::F32 => self.types.f32,
+            FloatTy::F64 => self.types.f64,
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 3adcdbe591f..e386d973ee4 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -1,8 +1,7 @@
 //! Diagnostics related methods for `TyS`.
 
-use crate::ty::sty::InferTy;
 use crate::ty::TyKind::*;
-use crate::ty::{TyCtxt, TyS};
+use crate::ty::{InferTy, TyCtxt, TyS};
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index f172790fe5f..c211f07bed8 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -1,7 +1,6 @@
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use crate::ty::diagnostics::suggest_constraining_type_param;
 use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
-use rustc_ast as ast;
 use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
 use rustc_errors::{pluralize, DiagnosticBuilder};
 use rustc_hir as hir;
@@ -48,7 +47,7 @@ pub enum TypeError<'tcx> {
 
     Sorts(ExpectedFound<Ty<'tcx>>),
     IntMismatch(ExpectedFound<ty::IntVarValue>),
-    FloatMismatch(ExpectedFound<ast::FloatTy>),
+    FloatMismatch(ExpectedFound<ty::FloatTy>),
     Traits(ExpectedFound<DefId>),
     VariadicMismatch(ExpectedFound<bool>),
 
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 860f91db2bf..94d75a469d3 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -1,6 +1,5 @@
 use crate::ich::StableHashingContext;
 use crate::ty::{self, Ty, TyCtxt};
-use rustc_ast as ast;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::DefId;
 use std::fmt::Debug;
@@ -24,9 +23,9 @@ where
 {
     BoolSimplifiedType,
     CharSimplifiedType,
-    IntSimplifiedType(ast::IntTy),
-    UintSimplifiedType(ast::UintTy),
-    FloatSimplifiedType(ast::FloatTy),
+    IntSimplifiedType(ty::IntTy),
+    UintSimplifiedType(ty::UintTy),
+    FloatSimplifiedType(ty::FloatTy),
     AdtSimplifiedType(D),
     StrSimplifiedType,
     ArraySimplifiedType,
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index ef467ed6514..ee837d88b7b 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -4,7 +4,7 @@ use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
 use crate::ty::subst::Subst;
 use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
 
-use rustc_ast::{self as ast, IntTy, UintTy};
+use rustc_ast as ast;
 use rustc_attr as attr;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir as hir;
@@ -30,6 +30,8 @@ use std::ops::Bound;
 pub trait IntegerExt {
     fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>;
     fn from_attr<C: HasDataLayout>(cx: &C, ity: attr::IntType) -> Integer;
+    fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> Integer;
+    fn from_uint_ty<C: HasDataLayout>(cx: &C, uty: ty::UintTy) -> Integer;
     fn repr_discr<'tcx>(
         tcx: TyCtxt<'tcx>,
         ty: Ty<'tcx>,
@@ -60,17 +62,38 @@ impl IntegerExt for Integer {
         let dl = cx.data_layout();
 
         match ity {
-            attr::SignedInt(IntTy::I8) | attr::UnsignedInt(UintTy::U8) => I8,
-            attr::SignedInt(IntTy::I16) | attr::UnsignedInt(UintTy::U16) => I16,
-            attr::SignedInt(IntTy::I32) | attr::UnsignedInt(UintTy::U32) => I32,
-            attr::SignedInt(IntTy::I64) | attr::UnsignedInt(UintTy::U64) => I64,
-            attr::SignedInt(IntTy::I128) | attr::UnsignedInt(UintTy::U128) => I128,
-            attr::SignedInt(IntTy::Isize) | attr::UnsignedInt(UintTy::Usize) => {
+            attr::SignedInt(ast::IntTy::I8) | attr::UnsignedInt(ast::UintTy::U8) => I8,
+            attr::SignedInt(ast::IntTy::I16) | attr::UnsignedInt(ast::UintTy::U16) => I16,
+            attr::SignedInt(ast::IntTy::I32) | attr::UnsignedInt(ast::UintTy::U32) => I32,
+            attr::SignedInt(ast::IntTy::I64) | attr::UnsignedInt(ast::UintTy::U64) => I64,
+            attr::SignedInt(ast::IntTy::I128) | attr::UnsignedInt(ast::UintTy::U128) => I128,
+            attr::SignedInt(ast::IntTy::Isize) | attr::UnsignedInt(ast::UintTy::Usize) => {
                 dl.ptr_sized_integer()
             }
         }
     }
 
+    fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> Integer {
+        match ity {
+            ty::IntTy::I8 => I8,
+            ty::IntTy::I16 => I16,
+            ty::IntTy::I32 => I32,
+            ty::IntTy::I64 => I64,
+            ty::IntTy::I128 => I128,
+            ty::IntTy::Isize => cx.data_layout().ptr_sized_integer(),
+        }
+    }
+    fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: ty::UintTy) -> Integer {
+        match ity {
+            ty::UintTy::U8 => I8,
+            ty::UintTy::U16 => I16,
+            ty::UintTy::U32 => I32,
+            ty::UintTy::U64 => I64,
+            ty::UintTy::U128 => I128,
+            ty::UintTy::Usize => cx.data_layout().ptr_sized_integer(),
+        }
+    }
+
     /// Finds the appropriate Integer type and signedness for the given
     /// signed discriminant range and `#[repr]` attribute.
     /// N.B.: `u128` values above `i128::MAX` will be treated as signed, but
@@ -487,11 +510,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                 self,
                 Scalar { value: Int(I32, false), valid_range: 0..=0x10FFFF },
             )),
-            ty::Int(ity) => scalar(Int(Integer::from_attr(dl, attr::SignedInt(ity)), true)),
-            ty::Uint(ity) => scalar(Int(Integer::from_attr(dl, attr::UnsignedInt(ity)), false)),
+            ty::Int(ity) => scalar(Int(Integer::from_int_ty(dl, ity), true)),
+            ty::Uint(ity) => scalar(Int(Integer::from_uint_ty(dl, ity), false)),
             ty::Float(fty) => scalar(match fty {
-                ast::FloatTy::F32 => F32,
-                ast::FloatTy::F64 => F64,
+                ty::FloatTy::F32 => F32,
+                ty::FloatTy::F64 => F64,
             }),
             ty::FnPtr(_) => {
                 let mut ptr = scalar_unit(Pointer);
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index c4d86716138..8e8caa46c38 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -65,7 +65,6 @@ use std::ptr;
 use std::str;
 
 pub use self::sty::BoundRegionKind::*;
-pub use self::sty::InferTy::*;
 pub use self::sty::RegionKind;
 pub use self::sty::RegionKind::*;
 pub use self::sty::TyKind::*;
@@ -74,13 +73,14 @@ pub use self::sty::{BoundRegion, BoundRegionKind, EarlyBoundRegion, FreeRegion,
 pub use self::sty::{CanonicalPolyFnSig, FnSig, GenSig, PolyFnSig, PolyGenSig};
 pub use self::sty::{ClosureSubsts, GeneratorSubsts, TypeAndMut, UpvarSubsts};
 pub use self::sty::{ClosureSubstsParts, GeneratorSubstsParts};
-pub use self::sty::{ConstVid, FloatVid, IntVid, RegionVid, TyVid};
-pub use self::sty::{ExistentialPredicate, InferTy, ParamConst, ParamTy, ProjectionTy};
+pub use self::sty::{ConstVid, RegionVid};
+pub use self::sty::{ExistentialPredicate, ParamConst, ParamTy, ProjectionTy};
 pub use self::sty::{ExistentialProjection, PolyExistentialProjection};
 pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
 pub use self::sty::{PolyTraitRef, TraitRef, TyKind};
 pub use crate::ty::diagnostics::*;
-pub use rustc_type_ir::{DebruijnIndex, TypeFlags, INNERMOST};
+pub use rustc_type_ir::InferTy::*;
+pub use rustc_type_ir::*;
 
 pub use self::binding::BindingMode;
 pub use self::binding::BindingMode::*;
@@ -421,14 +421,6 @@ impl Visibility {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, TyDecodable, TyEncodable, HashStable)]
-pub enum Variance {
-    Covariant,     // T<A> <: T<B> iff A <: B -- e.g., function return type
-    Invariant,     // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
-    Contravariant, // T<A> <: T<B> iff B <: A -- e.g., function param type
-    Bivariant,     // T<A> <: T<B>            -- e.g., unused type parameter
-}
-
 /// The crate variances map is computed during typeck and contains the
 /// variance of every item in the local crate. You should not use it
 /// directly, because to do so will make your pass dependent on the
@@ -443,66 +435,6 @@ pub struct CrateVariancesMap<'tcx> {
     pub variances: FxHashMap<DefId, &'tcx [ty::Variance]>,
 }
 
-impl Variance {
-    /// `a.xform(b)` combines the variance of a context with the
-    /// variance of a type with the following meaning. If we are in a
-    /// context with variance `a`, and we encounter a type argument in
-    /// a position with variance `b`, then `a.xform(b)` is the new
-    /// variance with which the argument appears.
-    ///
-    /// Example 1:
-    ///
-    ///     *mut Vec<i32>
-    ///
-    /// Here, the "ambient" variance starts as covariant. `*mut T` is
-    /// invariant with respect to `T`, so the variance in which the
-    /// `Vec<i32>` appears is `Covariant.xform(Invariant)`, which
-    /// yields `Invariant`. Now, the type `Vec<T>` is covariant with
-    /// respect to its type argument `T`, and hence the variance of
-    /// the `i32` here is `Invariant.xform(Covariant)`, which results
-    /// (again) in `Invariant`.
-    ///
-    /// Example 2:
-    ///
-    ///     fn(*const Vec<i32>, *mut Vec<i32)
-    ///
-    /// The ambient variance is covariant. A `fn` type is
-    /// contravariant with respect to its parameters, so the variance
-    /// within which both pointer types appear is
-    /// `Covariant.xform(Contravariant)`, or `Contravariant`. `*const
-    /// T` is covariant with respect to `T`, so the variance within
-    /// which the first `Vec<i32>` appears is
-    /// `Contravariant.xform(Covariant)` or `Contravariant`. The same
-    /// is true for its `i32` argument. In the `*mut T` case, the
-    /// variance of `Vec<i32>` is `Contravariant.xform(Invariant)`,
-    /// and hence the outermost type is `Invariant` with respect to
-    /// `Vec<i32>` (and its `i32` argument).
-    ///
-    /// Source: Figure 1 of "Taming the Wildcards:
-    /// Combining Definition- and Use-Site Variance" published in PLDI'11.
-    pub fn xform(self, v: ty::Variance) -> ty::Variance {
-        match (self, v) {
-            // Figure 1, column 1.
-            (ty::Covariant, ty::Covariant) => ty::Covariant,
-            (ty::Covariant, ty::Contravariant) => ty::Contravariant,
-            (ty::Covariant, ty::Invariant) => ty::Invariant,
-            (ty::Covariant, ty::Bivariant) => ty::Bivariant,
-
-            // Figure 1, column 2.
-            (ty::Contravariant, ty::Covariant) => ty::Contravariant,
-            (ty::Contravariant, ty::Contravariant) => ty::Covariant,
-            (ty::Contravariant, ty::Invariant) => ty::Invariant,
-            (ty::Contravariant, ty::Bivariant) => ty::Bivariant,
-
-            // Figure 1, column 3.
-            (ty::Invariant, _) => ty::Invariant,
-
-            // Figure 1, column 4.
-            (ty::Bivariant, _) => ty::Bivariant,
-        }
-    }
-}
-
 // Contains information needed to resolve types and (in the future) look up
 // the types of AST nodes.
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
@@ -780,8 +712,20 @@ pub fn place_to_string_for_capture(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) ->
 pub struct CaptureInfo<'tcx> {
     /// Expr Id pointing to use that resulted in selecting the current capture kind
     ///
+    /// Eg:
+    /// ```rust,no_run
+    /// let mut t = (0,1);
+    ///
+    /// let c = || {
+    ///     println!("{}",t); // L1
+    ///     t.1 = 4; // L2
+    /// };
+    /// ```
+    /// `capture_kind_expr_id` will point to the use on L2 and `path_expr_id` will point to the
+    /// use on L1.
+    ///
     /// If the user doesn't enable feature `capture_disjoint_fields` (RFC 2229) then, it is
-    /// possible that we don't see the use of a particular place resulting in expr_id being
+    /// possible that we don't see the use of a particular place resulting in capture_kind_expr_id being
     /// None. In such case we fallback on uvpars_mentioned for span.
     ///
     /// Eg:
@@ -795,7 +739,12 @@ pub struct CaptureInfo<'tcx> {
     ///
     /// In this example, if `capture_disjoint_fields` is **not** set, then x will be captured,
     /// but we won't see it being used during capture analysis, since it's essentially a discard.
-    pub expr_id: Option<hir::HirId>,
+    pub capture_kind_expr_id: Option<hir::HirId>,
+    /// Expr Id pointing to use that resulted the corresponding place being captured
+    ///
+    /// See `capture_kind_expr_id` for example.
+    ///
+    pub path_expr_id: Option<hir::HirId>,
 
     /// Capture mode that was selected
     pub capture_kind: UpvarCapture<'tcx>,
@@ -804,15 +753,6 @@ pub struct CaptureInfo<'tcx> {
 pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>;
 pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>;
 
-#[derive(Clone, Copy, PartialEq, Eq)]
-pub enum IntVarValue {
-    IntType(ast::IntTy),
-    UintType(ast::UintTy),
-}
-
-#[derive(Clone, Copy, PartialEq, Eq)]
-pub struct FloatVarValue(pub ast::FloatTy);
-
 impl ty::EarlyBoundRegion {
     /// Does this early bound region have a name? Early bound regions normally
     /// always have names except when using anonymous lifetimes (`'_`).
@@ -3122,6 +3062,57 @@ pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
     None
 }
 
+pub fn int_ty(ity: ast::IntTy) -> IntTy {
+    match ity {
+        ast::IntTy::Isize => IntTy::Isize,
+        ast::IntTy::I8 => IntTy::I8,
+        ast::IntTy::I16 => IntTy::I16,
+        ast::IntTy::I32 => IntTy::I32,
+        ast::IntTy::I64 => IntTy::I64,
+        ast::IntTy::I128 => IntTy::I128,
+    }
+}
+
+pub fn uint_ty(uty: ast::UintTy) -> UintTy {
+    match uty {
+        ast::UintTy::Usize => UintTy::Usize,
+        ast::UintTy::U8 => UintTy::U8,
+        ast::UintTy::U16 => UintTy::U16,
+        ast::UintTy::U32 => UintTy::U32,
+        ast::UintTy::U64 => UintTy::U64,
+        ast::UintTy::U128 => UintTy::U128,
+    }
+}
+
+pub fn float_ty(fty: ast::FloatTy) -> FloatTy {
+    match fty {
+        ast::FloatTy::F32 => FloatTy::F32,
+        ast::FloatTy::F64 => FloatTy::F64,
+    }
+}
+
+pub fn ast_int_ty(ity: IntTy) -> ast::IntTy {
+    match ity {
+        IntTy::Isize => ast::IntTy::Isize,
+        IntTy::I8 => ast::IntTy::I8,
+        IntTy::I16 => ast::IntTy::I16,
+        IntTy::I32 => ast::IntTy::I32,
+        IntTy::I64 => ast::IntTy::I64,
+        IntTy::I128 => ast::IntTy::I128,
+    }
+}
+
+pub fn ast_uint_ty(uty: UintTy) -> ast::UintTy {
+    match uty {
+        UintTy::Usize => ast::UintTy::Usize,
+        UintTy::U8 => ast::UintTy::U8,
+        UintTy::U16 => ast::UintTy::U16,
+        UintTy::U32 => ast::UintTy::U32,
+        UintTy::U64 => ast::UintTy::U64,
+        UintTy::U128 => ast::UintTy::U128,
+    }
+}
+
 pub fn provide(providers: &mut ty::query::Providers) {
     context::provide(providers);
     erase_regions::provide(providers);
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 8911de41c6d..4937fdd7314 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -3,7 +3,6 @@ use crate::mir::interpret::{AllocId, ConstValue, GlobalAlloc, Pointer, Scalar};
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
 use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
 use rustc_apfloat::ieee::{Double, Single};
-use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
@@ -557,14 +556,19 @@ pub trait PrettyPrinter<'tcx>:
             }
             ty::FnPtr(ref bare_fn) => p!(print(bare_fn)),
             ty::Infer(infer_ty) => {
+                let verbose = self.tcx().sess.verbose();
                 if let ty::TyVar(ty_vid) = infer_ty {
                     if let Some(name) = self.infer_ty_name(ty_vid) {
                         p!(write("{}", name))
                     } else {
-                        p!(write("{}", infer_ty))
+                        if verbose {
+                            p!(write("{:?}", infer_ty))
+                        } else {
+                            p!(write("{}", infer_ty))
+                        }
                     }
                 } else {
-                    p!(write("{}", infer_ty))
+                    if verbose { p!(write("{:?}", infer_ty)) } else { p!(write("{}", infer_ty)) }
                 }
             }
             ty::Error(_) => p!("[type error]"),
@@ -968,7 +972,7 @@ pub trait PrettyPrinter<'tcx>:
                     ty::TyS {
                         kind:
                             ty::Array(
-                                ty::TyS { kind: ty::Uint(ast::UintTy::U8), .. },
+                                ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. },
                                 ty::Const {
                                     val: ty::ConstKind::Value(ConstValue::Scalar(int)),
                                     ..
@@ -997,10 +1001,10 @@ pub trait PrettyPrinter<'tcx>:
             (Scalar::Int(int), ty::Bool) if int == ScalarInt::FALSE => p!("false"),
             (Scalar::Int(int), ty::Bool) if int == ScalarInt::TRUE => p!("true"),
             // Float
-            (Scalar::Int(int), ty::Float(ast::FloatTy::F32)) => {
+            (Scalar::Int(int), ty::Float(ty::FloatTy::F32)) => {
                 p!(write("{}f32", Single::try_from(int).unwrap()))
             }
-            (Scalar::Int(int), ty::Float(ast::FloatTy::F64)) => {
+            (Scalar::Int(int), ty::Float(ty::FloatTy::F64)) => {
                 p!(write("{}f64", Double::try_from(int).unwrap()))
             }
             // Int
@@ -1246,7 +1250,7 @@ pub struct FmtPrinterData<'a, 'tcx, F> {
 
     pub region_highlight_mode: RegionHighlightMode,
 
-    pub name_resolver: Option<Box<&'a dyn Fn(ty::sty::TyVid) -> Option<String>>>,
+    pub name_resolver: Option<Box<&'a dyn Fn(ty::TyVid) -> Option<String>>>,
 }
 
 impl<F> Deref for FmtPrinter<'a, 'tcx, F> {
@@ -2007,21 +2011,6 @@ define_print_and_forward_display! {
         p!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output()));
     }
 
-    ty::InferTy {
-        if cx.tcx().sess.verbose() {
-            p!(write("{:?}", self));
-            return Ok(cx);
-        }
-        match *self {
-            ty::TyVar(_) => p!("_"),
-            ty::IntVar(_) => p!(write("{}", "{integer}")),
-            ty::FloatVar(_) => p!(write("{}", "{float}")),
-            ty::FreshTy(v) => p!(write("FreshTy({})", v)),
-            ty::FreshIntTy(v) => p!(write("FreshIntTy({})", v)),
-            ty::FreshFloatTy(v) => p!(write("FreshFloatTy({})", v))
-        }
-    }
-
     ty::TraitRef<'tcx> {
         p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path()))
     }
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 44c173e356d..0ca94a9f180 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -111,81 +111,24 @@ impl fmt::Debug for ty::FreeRegion {
     }
 }
 
-impl fmt::Debug for ty::Variance {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.write_str(match *self {
-            ty::Covariant => "+",
-            ty::Contravariant => "-",
-            ty::Invariant => "o",
-            ty::Bivariant => "*",
-        })
-    }
-}
-
 impl fmt::Debug for ty::FnSig<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "({:?}; c_variadic: {})->{:?}", self.inputs(), self.c_variadic, self.output())
     }
 }
 
-impl fmt::Debug for ty::TyVid {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "_#{}t", self.index)
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "_#{}c", self.index)
     }
 }
 
-impl fmt::Debug for ty::IntVid {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "_#{}i", self.index)
-    }
-}
-
-impl fmt::Debug for ty::FloatVid {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "_#{}f", self.index)
-    }
-}
-
 impl fmt::Debug for ty::RegionVid {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "'_#{}r", self.index())
     }
 }
 
-impl fmt::Debug for ty::InferTy {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            ty::TyVar(ref v) => v.fmt(f),
-            ty::IntVar(ref v) => v.fmt(f),
-            ty::FloatVar(ref v) => v.fmt(f),
-            ty::FreshTy(v) => write!(f, "FreshTy({:?})", v),
-            ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
-            ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v),
-        }
-    }
-}
-
-impl fmt::Debug for ty::IntVarValue {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            ty::IntType(ref v) => v.fmt(f),
-            ty::UintType(ref v) => v.fmt(f),
-        }
-    }
-}
-
-impl fmt::Debug for ty::FloatVarValue {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0.fmt(f)
-    }
-}
-
 impl fmt::Debug for ty::TraitRef<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         with_no_trimmed_paths(|| fmt::Display::fmt(self, f))
@@ -274,7 +217,7 @@ TrivialTypeFoldableAndLiftImpls! {
     u64,
     String,
     crate::middle::region::Scope,
-    ::rustc_ast::FloatTy,
+    crate::ty::FloatTy,
     ::rustc_ast::InlineAsmOptions,
     ::rustc_ast::InlineAsmTemplatePiece,
     ::rustc_ast::NodeId,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index e53977b5eb9..9cec0eb5be3 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -2,17 +2,16 @@
 
 #![allow(rustc::usage_of_ty_tykind)]
 
-use self::InferTy::*;
 use self::TyKind::*;
 
 use crate::infer::canonical::Canonical;
 use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
+use crate::ty::InferTy::{self, *};
 use crate::ty::{
     self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable, WithConstness,
 };
 use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS};
 use polonius_engine::Atom;
-use rustc_ast as ast;
 use rustc_data_structures::captures::Captures;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -104,13 +103,13 @@ pub enum TyKind<'tcx> {
     Char,
 
     /// A primitive signed integer type. For example, `i32`.
-    Int(ast::IntTy),
+    Int(ty::IntTy),
 
     /// A primitive unsigned integer type. For example, `u32`.
-    Uint(ast::UintTy),
+    Uint(ty::UintTy),
 
     /// A primitive floating-point type. For example, `f64`.
-    Float(ast::FloatTy),
+    Float(ty::FloatTy),
 
     /// Algebraic data types (ADT). For example: structures, enumerations and unions.
     ///
@@ -1426,12 +1425,6 @@ pub struct EarlyBoundRegion {
     pub name: Symbol,
 }
 
-/// A **ty**pe **v**ariable **ID**.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
-pub struct TyVid {
-    pub index: u32,
-}
-
 /// A **`const`** **v**ariable **ID**.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 pub struct ConstVid<'tcx> {
@@ -1439,18 +1432,6 @@ pub struct ConstVid<'tcx> {
     pub phantom: PhantomData<&'tcx ()>,
 }
 
-/// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
-pub struct IntVid {
-    pub index: u32,
-}
-
-/// An **float**ing-point (`f32` or `f64`) type **v**ariable **ID**.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
-pub struct FloatVid {
-    pub index: u32,
-}
-
 rustc_index::newtype_index! {
     /// A **region** (lifetime) **v**ariable **ID**.
     pub struct RegionVid {
@@ -1464,43 +1445,6 @@ impl Atom for RegionVid {
     }
 }
 
-/// A placeholder for a type that hasn't been inferred yet.
-///
-/// E.g., if we have an empty array (`[]`), then we create a fresh
-/// type variable for the element type since we won't know until it's
-/// used what the element type is supposed to be.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable)]
-pub enum InferTy {
-    /// A type variable.
-    TyVar(TyVid),
-    /// An integral type variable (`{integer}`).
-    ///
-    /// These are created when the compiler sees an integer literal like
-    /// `1` that could be several different types (`u8`, `i32`, `u32`, etc.).
-    /// We don't know until it's used what type it's supposed to be, so
-    /// we create a fresh type variable.
-    IntVar(IntVid),
-    /// A floating-point type variable (`{float}`).
-    ///
-    /// These are created when the compiler sees an float literal like
-    /// `1.0` that could be either an `f32` or an `f64`.
-    /// We don't know until it's used what type it's supposed to be, so
-    /// we create a fresh type variable.
-    FloatVar(FloatVid),
-
-    /// A [`FreshTy`][Self::FreshTy] is one that is generated as a replacement
-    /// for an unbound type variable. This is convenient for caching etc. See
-    /// `rustc_infer::infer::freshen` for more details.
-    ///
-    /// Compare with [`TyVar`][Self::TyVar].
-    FreshTy(u32),
-    /// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`IntVar`][Self::IntVar].
-    FreshIntTy(u32),
-    /// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`FloatVar`][Self::FloatVar].
-    FreshFloatTy(u32),
-}
-
 rustc_index::newtype_index! {
     pub struct BoundVar { .. }
 }
@@ -1853,7 +1797,7 @@ impl<'tcx> TyS<'tcx> {
     pub fn sequence_element_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match self.kind() {
             Array(ty, _) | Slice(ty) => ty,
-            Str => tcx.mk_mach_uint(ast::UintTy::U8),
+            Str => tcx.mk_mach_uint(ty::UintTy::U8),
             _ => bug!("`sequence_element_type` called on non-sequence value: {}", self),
         }
     }
@@ -1993,7 +1937,7 @@ impl<'tcx> TyS<'tcx> {
 
     #[inline]
     pub fn is_ptr_sized_integral(&self) -> bool {
-        matches!(self.kind(), Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize))
+        matches!(self.kind(), Int(ty::IntTy::Isize) | Uint(ty::UintTy::Usize))
     }
 
     #[inline]
@@ -2181,9 +2125,9 @@ impl<'tcx> TyS<'tcx> {
     pub fn to_opt_closure_kind(&self) -> Option<ty::ClosureKind> {
         match self.kind() {
             Int(int_ty) => match int_ty {
-                ast::IntTy::I8 => Some(ty::ClosureKind::Fn),
-                ast::IntTy::I16 => Some(ty::ClosureKind::FnMut),
-                ast::IntTy::I32 => Some(ty::ClosureKind::FnOnce),
+                ty::IntTy::I8 => Some(ty::ClosureKind::Fn),
+                ty::IntTy::I16 => Some(ty::ClosureKind::FnMut),
+                ty::IntTy::I32 => Some(ty::ClosureKind::FnOnce),
                 _ => bug!("cannot convert type `{:?}` to a closure kind", self),
             },
 
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index a64580336ad..8edde8794ed 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -34,7 +34,7 @@ impl<'tcx> fmt::Display for Discr<'tcx> {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self.ty.kind() {
             ty::Int(ity) => {
-                let size = ty::tls::with(|tcx| Integer::from_attr(&tcx, SignedInt(ity)).size());
+                let size = ty::tls::with(|tcx| Integer::from_int_ty(&tcx, ity).size());
                 let x = self.val;
                 // sign extend the raw representation to be an i128
                 let x = size.sign_extend(x) as i128;
@@ -59,8 +59,8 @@ fn unsigned_max(size: Size) -> u128 {
 
 fn int_size_and_signed<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (Size, bool) {
     let (int, signed) = match *ty.kind() {
-        Int(ity) => (Integer::from_attr(&tcx, SignedInt(ity)), true),
-        Uint(uty) => (Integer::from_attr(&tcx, UnsignedInt(uty)), false),
+        Int(ity) => (Integer::from_int_ty(&tcx, ity), true),
+        Uint(uty) => (Integer::from_uint_ty(&tcx, uty), false),
         _ => bug!("non integer discriminant"),
     };
     (int.size(), signed)
@@ -642,8 +642,8 @@ impl<'tcx> ty::TyS<'tcx> {
             }
             ty::Char => Some(std::char::MAX as u128),
             ty::Float(fty) => Some(match fty {
-                ast::FloatTy::F32 => rustc_apfloat::ieee::Single::INFINITY.to_bits(),
-                ast::FloatTy::F64 => rustc_apfloat::ieee::Double::INFINITY.to_bits(),
+                ty::FloatTy::F32 => rustc_apfloat::ieee::Single::INFINITY.to_bits(),
+                ty::FloatTy::F64 => rustc_apfloat::ieee::Double::INFINITY.to_bits(),
             }),
             _ => None,
         };
@@ -661,8 +661,8 @@ impl<'tcx> ty::TyS<'tcx> {
             }
             ty::Char => Some(0),
             ty::Float(fty) => Some(match fty {
-                ast::FloatTy::F32 => (-::rustc_apfloat::ieee::Single::INFINITY).to_bits(),
-                ast::FloatTy::F64 => (-::rustc_apfloat::ieee::Double::INFINITY).to_bits(),
+                ty::FloatTy::F32 => (-::rustc_apfloat::ieee::Single::INFINITY).to_bits(),
+                ty::FloatTy::F64 => (-::rustc_apfloat::ieee::Double::INFINITY).to_bits(),
             }),
             _ => None,
         };
diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs
index 6d224bcc50b..128d8cff95e 100644
--- a/compiler/rustc_mir/src/interpret/cast.rs
+++ b/compiler/rustc_mir/src/interpret/cast.rs
@@ -2,13 +2,11 @@ use std::convert::TryFrom;
 
 use rustc_apfloat::ieee::{Double, Single};
 use rustc_apfloat::{Float, FloatConvert};
-use rustc_ast::FloatTy;
-use rustc_attr as attr;
 use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
 use rustc_middle::mir::CastKind;
 use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
-use rustc_middle::ty::{self, Ty, TypeAndMut};
+use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut};
 use rustc_span::symbol::sym;
 use rustc_target::abi::{Integer, LayoutOf, Variants};
 
@@ -203,8 +201,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         match *cast_ty.kind() {
             Int(_) | Uint(_) | RawPtr(_) => {
                 let size = match *cast_ty.kind() {
-                    Int(t) => Integer::from_attr(self, attr::IntType::SignedInt(t)).size(),
-                    Uint(t) => Integer::from_attr(self, attr::IntType::UnsignedInt(t)).size(),
+                    Int(t) => Integer::from_int_ty(self, t).size(),
+                    Uint(t) => Integer::from_uint_ty(self, t).size(),
                     RawPtr(_) => self.pointer_size(),
                     _ => bug!(),
                 };
@@ -235,7 +233,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         match *dest_ty.kind() {
             // float -> uint
             Uint(t) => {
-                let size = Integer::from_attr(self, attr::IntType::UnsignedInt(t)).size();
+                let size = Integer::from_uint_ty(self, t).size();
                 // `to_u128` is a saturating cast, which is what we need
                 // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r).
                 let v = f.to_u128(size.bits_usize()).value;
@@ -244,7 +242,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
             // float -> int
             Int(t) => {
-                let size = Integer::from_attr(self, attr::IntType::SignedInt(t)).size();
+                let size = Integer::from_int_ty(self, t).size();
                 // `to_i128` is a saturating cast, which is what we need
                 // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r).
                 let v = f.to_i128(size.bits_usize()).value;
diff --git a/compiler/rustc_mir/src/interpret/operator.rs b/compiler/rustc_mir/src/interpret/operator.rs
index fc266fa74bf..f5081655015 100644
--- a/compiler/rustc_mir/src/interpret/operator.rs
+++ b/compiler/rustc_mir/src/interpret/operator.rs
@@ -1,10 +1,9 @@
 use std::convert::TryFrom;
 
 use rustc_apfloat::Float;
-use rustc_ast::FloatTy;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{InterpResult, Scalar};
-use rustc_middle::ty::{self, layout::TyAndLayout, Ty};
+use rustc_middle::ty::{self, layout::TyAndLayout, FloatTy, Ty};
 use rustc_target::abi::LayoutOf;
 
 use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy};
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index f30745d7185..ddfaeafc07c 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -15,7 +15,6 @@
 use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
 use crate::build::Builder;
 use crate::thir::{self, *};
-use rustc_attr::{SignedInt, UnsignedInt};
 use rustc_hir::RangeEnd;
 use rustc_middle::mir::Place;
 use rustc_middle::ty;
@@ -203,13 +202,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
                     }
                     ty::Int(ity) => {
-                        let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
+                        let size = Integer::from_int_ty(&tcx, ity).size();
                         let max = size.truncate(u128::MAX);
                         let bias = 1u128 << (size.bits() - 1);
                         (Some((0, max, size)), bias)
                     }
                     ty::Uint(uty) => {
-                        let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size();
+                        let size = Integer::from_uint_ty(&tcx, uty).size();
                         let max = size.truncate(u128::MAX);
                         (Some((0, max, size)), 0)
                     }
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index dfe82317f48..969f7d1e3a4 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -39,7 +39,7 @@ crate fn lit_to_const<'tcx>(
             let id = tcx.allocate_bytes(data);
             ConstValue::Scalar(Scalar::Ptr(id.into()))
         }
-        (ast::LitKind::Byte(n), ty::Uint(ast::UintTy::U8)) => {
+        (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
             ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
         }
         (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
@@ -56,11 +56,11 @@ crate fn lit_to_const<'tcx>(
     Ok(ty::Const::from_value(tcx, lit, ty))
 }
 
-fn parse_float<'tcx>(num: Symbol, fty: ast::FloatTy, neg: bool) -> Result<ConstValue<'tcx>, ()> {
+fn parse_float<'tcx>(num: Symbol, fty: ty::FloatTy, neg: bool) -> Result<ConstValue<'tcx>, ()> {
     let num = num.as_str();
     use rustc_apfloat::ieee::{Double, Single};
     let scalar = match fty {
-        ast::FloatTy::F32 => {
+        ty::FloatTy::F32 => {
             num.parse::<f32>().map_err(|_| ())?;
             let mut f = num.parse::<Single>().unwrap_or_else(|e| {
                 panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
@@ -70,7 +70,7 @@ fn parse_float<'tcx>(num: Symbol, fty: ast::FloatTy, neg: bool) -> Result<ConstV
             }
             Scalar::from_f32(f)
         }
-        ast::FloatTy::F64 => {
+        ty::FloatTy::F64 => {
             num.parse::<f64>().map_err(|_| ())?;
             let mut f = num.parse::<Double>().unwrap_or_else(|e| {
                 panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e)
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index db2fa5730a3..e67166c99c8 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -52,7 +52,6 @@ use super::{FieldPat, Pat, PatKind, PatRange};
 use rustc_data_structures::captures::Captures;
 use rustc_index::vec::Idx;
 
-use rustc_attr::{SignedInt, UnsignedInt};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{HirId, RangeEnd};
 use rustc_middle::mir::interpret::ConstValue;
@@ -103,10 +102,10 @@ impl IntRange {
             ty::Bool => Some((Size::from_bytes(1), 0)),
             ty::Char => Some((Size::from_bytes(4), 0)),
             ty::Int(ity) => {
-                let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
+                let size = Integer::from_int_ty(&tcx, ity).size();
                 Some((size, 1u128 << (size.bits() as u128 - 1)))
             }
-            ty::Uint(uty) => Some((Integer::from_attr(&tcx, UnsignedInt(uty)).size(), 0)),
+            ty::Uint(uty) => Some((Integer::from_uint_ty(&tcx, uty).size(), 0)),
             _ => None,
         }
     }
@@ -167,7 +166,7 @@ impl IntRange {
     fn signed_bias(tcx: TyCtxt<'_>, ty: Ty<'_>) -> u128 {
         match *ty.kind() {
             ty::Int(ity) => {
-                let bits = Integer::from_attr(&tcx, SignedInt(ity)).size().bits() as u128;
+                let bits = Integer::from_int_ty(&tcx, ity).size().bits() as u128;
                 1u128 << (bits - 1)
             }
             _ => 0,
@@ -959,13 +958,13 @@ impl<'tcx> SplitWildcard<'tcx> {
                 smallvec![NonExhaustive]
             }
             &ty::Int(ity) => {
-                let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128;
+                let bits = Integer::from_int_ty(&cx.tcx, ity).size().bits() as u128;
                 let min = 1u128 << (bits - 1);
                 let max = min - 1;
                 smallvec![make_range(min, max)]
             }
             &ty::Uint(uty) => {
-                let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size();
+                let size = Integer::from_uint_ty(&cx.tcx, uty).size();
                 let max = size.truncate(u128::MAX);
                 smallvec![make_range(0, max)]
             }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 7e9a3a37278..7186e26be80 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -9,7 +9,6 @@ pub(crate) use self::check_match::check_match;
 
 use crate::thir::util::UserAnnotatedTyHelpers;
 
-use rustc_ast as ast;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@@ -1069,20 +1068,19 @@ crate fn compare_const_vals<'tcx>(
     if let (Some(a), Some(b)) = (a_bits, b_bits) {
         use rustc_apfloat::Float;
         return match *ty.kind() {
-            ty::Float(ast::FloatTy::F32) => {
+            ty::Float(ty::FloatTy::F32) => {
                 let l = rustc_apfloat::ieee::Single::from_bits(a);
                 let r = rustc_apfloat::ieee::Single::from_bits(b);
                 l.partial_cmp(&r)
             }
-            ty::Float(ast::FloatTy::F64) => {
+            ty::Float(ty::FloatTy::F64) => {
                 let l = rustc_apfloat::ieee::Double::from_bits(a);
                 let r = rustc_apfloat::ieee::Double::from_bits(b);
                 l.partial_cmp(&r)
             }
             ty::Int(ity) => {
-                use rustc_attr::SignedInt;
                 use rustc_middle::ty::layout::IntegerExt;
-                let size = rustc_target::abi::Integer::from_attr(&tcx, SignedInt(ity)).size();
+                let size = rustc_target::abi::Integer::from_int_ty(&tcx, ity).size();
                 let a = size.sign_extend(a);
                 let b = size.sign_extend(b);
                 Some((a as i128).cmp(&(b as i128)))
diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs
index ee90e9c54f6..0f4bb635eee 100644
--- a/compiler/rustc_passes/src/intrinsicck.rs
+++ b/compiler/rustc_passes/src/intrinsicck.rs
@@ -1,4 +1,4 @@
-use rustc_ast::{FloatTy, InlineAsmTemplatePiece, IntTy, UintTy};
+use rustc_ast::InlineAsmTemplatePiece;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -7,7 +7,7 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_index::vec::Idx;
 use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, UintTy};
 use rustc_session::lint;
 use rustc_span::{sym, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::{Pointer, VariantIdx};
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 7b90e5b611c..2e7c9701c0c 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -622,6 +622,7 @@ symbols! {
         intel,
         into_iter,
         into_result,
+        into_trait,
         intra_doc_pointers,
         intrinsics,
         irrefutable_let_patterns,
@@ -1159,6 +1160,8 @@ symbols! {
         truncf32,
         truncf64,
         try_blocks,
+        try_from_trait,
+        try_into_trait,
         try_trait,
         tt,
         tuple,
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 7b6e6ad0696..c84e2cb45a6 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -1,4 +1,3 @@
-use rustc_ast::{FloatTy, IntTy, UintTy};
 use rustc_data_structures::base_n;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
@@ -6,7 +5,7 @@ use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
 use rustc_middle::ty::print::{Print, Printer};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
 use rustc_target::spec::abi::Abi;
 
 use std::fmt::Write;
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index ad229e03b0b..b587ed6487e 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -609,9 +609,29 @@ where
 /// Tries to unify two abstract constants using structural equality.
 pub(super) fn try_unify<'tcx>(
     tcx: TyCtxt<'tcx>,
-    a: AbstractConst<'tcx>,
-    b: AbstractConst<'tcx>,
+    mut a: AbstractConst<'tcx>,
+    mut b: AbstractConst<'tcx>,
 ) -> bool {
+    // We substitute generics repeatedly to allow AbstractConsts to unify where a
+    // ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g.
+    // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
+    while let Node::Leaf(a_ct) = a.root() {
+        let a_ct = a_ct.subst(tcx, a.substs);
+        match AbstractConst::from_const(tcx, a_ct) {
+            Ok(Some(a_act)) => a = a_act,
+            Ok(None) => break,
+            Err(_) => return true,
+        }
+    }
+    while let Node::Leaf(b_ct) = b.root() {
+        let b_ct = b_ct.subst(tcx, b.substs);
+        match AbstractConst::from_const(tcx, b_ct) {
+            Ok(Some(b_act)) => b = b_act,
+            Ok(None) => break,
+            Err(_) => return true,
+        }
+    }
+
     match (a.root(), b.root()) {
         (Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
             let a_ct = a_ct.subst(tcx, a.substs);
@@ -632,8 +652,6 @@ pub(super) fn try_unify<'tcx>(
                 // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
                 // means that we only allow inference variables if they are equal.
                 (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val,
-                // We may want to instead recurse into unevaluated constants here. That may require some
-                // care to prevent infinite recursion, so let's just ignore this for now.
                 (
                     ty::ConstKind::Unevaluated(a_def, a_substs, None),
                     ty::ConstKind::Unevaluated(b_def, b_substs, None),
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 1893d74335a..bb48ed93618 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -346,26 +346,26 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
                 (ty::Char, Scalar(Char)) => true,
                 (ty::Int(ty1), Scalar(Int(ty2))) => matches!(
                     (ty1, ty2),
-                    (ast::IntTy::Isize, chalk_ir::IntTy::Isize)
-                        | (ast::IntTy::I8, chalk_ir::IntTy::I8)
-                        | (ast::IntTy::I16, chalk_ir::IntTy::I16)
-                        | (ast::IntTy::I32, chalk_ir::IntTy::I32)
-                        | (ast::IntTy::I64, chalk_ir::IntTy::I64)
-                        | (ast::IntTy::I128, chalk_ir::IntTy::I128)
+                    (ty::IntTy::Isize, chalk_ir::IntTy::Isize)
+                        | (ty::IntTy::I8, chalk_ir::IntTy::I8)
+                        | (ty::IntTy::I16, chalk_ir::IntTy::I16)
+                        | (ty::IntTy::I32, chalk_ir::IntTy::I32)
+                        | (ty::IntTy::I64, chalk_ir::IntTy::I64)
+                        | (ty::IntTy::I128, chalk_ir::IntTy::I128)
                 ),
                 (ty::Uint(ty1), Scalar(Uint(ty2))) => matches!(
                     (ty1, ty2),
-                    (ast::UintTy::Usize, chalk_ir::UintTy::Usize)
-                        | (ast::UintTy::U8, chalk_ir::UintTy::U8)
-                        | (ast::UintTy::U16, chalk_ir::UintTy::U16)
-                        | (ast::UintTy::U32, chalk_ir::UintTy::U32)
-                        | (ast::UintTy::U64, chalk_ir::UintTy::U64)
-                        | (ast::UintTy::U128, chalk_ir::UintTy::U128)
+                    (ty::UintTy::Usize, chalk_ir::UintTy::Usize)
+                        | (ty::UintTy::U8, chalk_ir::UintTy::U8)
+                        | (ty::UintTy::U16, chalk_ir::UintTy::U16)
+                        | (ty::UintTy::U32, chalk_ir::UintTy::U32)
+                        | (ty::UintTy::U64, chalk_ir::UintTy::U64)
+                        | (ty::UintTy::U128, chalk_ir::UintTy::U128)
                 ),
                 (ty::Float(ty1), Scalar(Float(ty2))) => matches!(
                     (ty1, ty2),
-                    (ast::FloatTy::F32, chalk_ir::FloatTy::F32)
-                        | (ast::FloatTy::F64, chalk_ir::FloatTy::F64)
+                    (ty::FloatTy::F32, chalk_ir::FloatTy::F32)
+                        | (ty::FloatTy::F64, chalk_ir::FloatTy::F64)
                 ),
                 (&ty::Tuple(substs), Tuple(len, _)) => substs.len() == *len,
                 (&ty::Array(..), Array(..)) => true,
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 48d47054a41..2a1a3f57e23 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -233,8 +233,6 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq<RustInterner<'tcx>>>
 
 impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'tcx>> {
-        use rustc_ast as ast;
-
         let int = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Int(i));
         let uint = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(i));
         let float = |f| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Float(f));
@@ -243,24 +241,24 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
             ty::Bool => chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Bool),
             ty::Char => chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Char),
             ty::Int(ty) => match ty {
-                ast::IntTy::Isize => int(chalk_ir::IntTy::Isize),
-                ast::IntTy::I8 => int(chalk_ir::IntTy::I8),
-                ast::IntTy::I16 => int(chalk_ir::IntTy::I16),
-                ast::IntTy::I32 => int(chalk_ir::IntTy::I32),
-                ast::IntTy::I64 => int(chalk_ir::IntTy::I64),
-                ast::IntTy::I128 => int(chalk_ir::IntTy::I128),
+                ty::IntTy::Isize => int(chalk_ir::IntTy::Isize),
+                ty::IntTy::I8 => int(chalk_ir::IntTy::I8),
+                ty::IntTy::I16 => int(chalk_ir::IntTy::I16),
+                ty::IntTy::I32 => int(chalk_ir::IntTy::I32),
+                ty::IntTy::I64 => int(chalk_ir::IntTy::I64),
+                ty::IntTy::I128 => int(chalk_ir::IntTy::I128),
             },
             ty::Uint(ty) => match ty {
-                ast::UintTy::Usize => uint(chalk_ir::UintTy::Usize),
-                ast::UintTy::U8 => uint(chalk_ir::UintTy::U8),
-                ast::UintTy::U16 => uint(chalk_ir::UintTy::U16),
-                ast::UintTy::U32 => uint(chalk_ir::UintTy::U32),
-                ast::UintTy::U64 => uint(chalk_ir::UintTy::U64),
-                ast::UintTy::U128 => uint(chalk_ir::UintTy::U128),
+                ty::UintTy::Usize => uint(chalk_ir::UintTy::Usize),
+                ty::UintTy::U8 => uint(chalk_ir::UintTy::U8),
+                ty::UintTy::U16 => uint(chalk_ir::UintTy::U16),
+                ty::UintTy::U32 => uint(chalk_ir::UintTy::U32),
+                ty::UintTy::U64 => uint(chalk_ir::UintTy::U64),
+                ty::UintTy::U128 => uint(chalk_ir::UintTy::U128),
             },
             ty::Float(ty) => match ty {
-                ast::FloatTy::F32 => float(chalk_ir::FloatTy::F32),
-                ast::FloatTy::F64 => float(chalk_ir::FloatTy::F64),
+                ty::FloatTy::F32 => float(chalk_ir::FloatTy::F32),
+                ty::FloatTy::F64 => float(chalk_ir::FloatTy::F64),
             },
             ty::Adt(def, substs) => {
                 chalk_ir::TyKind::Adt(chalk_ir::AdtId(def), substs.lower_into(interner))
@@ -347,24 +345,24 @@ impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty<RustInterner<'tcx>> {
                 chalk_ir::Scalar::Bool => ty::Bool,
                 chalk_ir::Scalar::Char => ty::Char,
                 chalk_ir::Scalar::Int(int_ty) => match int_ty {
-                    chalk_ir::IntTy::Isize => ty::Int(ast::IntTy::Isize),
-                    chalk_ir::IntTy::I8 => ty::Int(ast::IntTy::I8),
-                    chalk_ir::IntTy::I16 => ty::Int(ast::IntTy::I16),
-                    chalk_ir::IntTy::I32 => ty::Int(ast::IntTy::I32),
-                    chalk_ir::IntTy::I64 => ty::Int(ast::IntTy::I64),
-                    chalk_ir::IntTy::I128 => ty::Int(ast::IntTy::I128),
+                    chalk_ir::IntTy::Isize => ty::Int(ty::IntTy::Isize),
+                    chalk_ir::IntTy::I8 => ty::Int(ty::IntTy::I8),
+                    chalk_ir::IntTy::I16 => ty::Int(ty::IntTy::I16),
+                    chalk_ir::IntTy::I32 => ty::Int(ty::IntTy::I32),
+                    chalk_ir::IntTy::I64 => ty::Int(ty::IntTy::I64),
+                    chalk_ir::IntTy::I128 => ty::Int(ty::IntTy::I128),
                 },
                 chalk_ir::Scalar::Uint(int_ty) => match int_ty {
-                    chalk_ir::UintTy::Usize => ty::Uint(ast::UintTy::Usize),
-                    chalk_ir::UintTy::U8 => ty::Uint(ast::UintTy::U8),
-                    chalk_ir::UintTy::U16 => ty::Uint(ast::UintTy::U16),
-                    chalk_ir::UintTy::U32 => ty::Uint(ast::UintTy::U32),
-                    chalk_ir::UintTy::U64 => ty::Uint(ast::UintTy::U64),
-                    chalk_ir::UintTy::U128 => ty::Uint(ast::UintTy::U128),
+                    chalk_ir::UintTy::Usize => ty::Uint(ty::UintTy::Usize),
+                    chalk_ir::UintTy::U8 => ty::Uint(ty::UintTy::U8),
+                    chalk_ir::UintTy::U16 => ty::Uint(ty::UintTy::U16),
+                    chalk_ir::UintTy::U32 => ty::Uint(ty::UintTy::U32),
+                    chalk_ir::UintTy::U64 => ty::Uint(ty::UintTy::U64),
+                    chalk_ir::UintTy::U128 => ty::Uint(ty::UintTy::U128),
                 },
                 chalk_ir::Scalar::Float(float_ty) => match float_ty {
-                    chalk_ir::FloatTy::F32 => ty::Float(ast::FloatTy::F32),
-                    chalk_ir::FloatTy::F64 => ty::Float(ast::FloatTy::F64),
+                    chalk_ir::FloatTy::F32 => ty::Float(ty::FloatTy::F32),
+                    chalk_ir::FloatTy::F64 => ty::Float(ty::FloatTy::F64),
                 },
             },
             TyKind::Array(ty, c) => {
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index d50451b7794..3f64bd89997 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -12,3 +12,4 @@ bitflags = "1.2.1"
 rustc_index = { path = "../rustc_index" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 37abb4496ac..7e70af21c03 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -4,8 +4,13 @@
 
 #[macro_use]
 extern crate bitflags;
+#[macro_use]
+extern crate rustc_macros;
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::unify::{EqUnifyValue, UnifyKey};
+use std::fmt;
+use std::mem::discriminant;
 
 bitflags! {
     /// Flags that we track on types. These flags are propagated upwards
@@ -197,8 +202,409 @@ impl DebruijnIndex {
     }
 }
 
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Encodable, Decodable)]
+pub enum IntTy {
+    Isize,
+    I8,
+    I16,
+    I32,
+    I64,
+    I128,
+}
+
+impl IntTy {
+    pub fn name_str(&self) -> &'static str {
+        match *self {
+            IntTy::Isize => "isize",
+            IntTy::I8 => "i8",
+            IntTy::I16 => "i16",
+            IntTy::I32 => "i32",
+            IntTy::I64 => "i64",
+            IntTy::I128 => "i128",
+        }
+    }
+
+    pub fn bit_width(&self) -> Option<u64> {
+        Some(match *self {
+            IntTy::Isize => return None,
+            IntTy::I8 => 8,
+            IntTy::I16 => 16,
+            IntTy::I32 => 32,
+            IntTy::I64 => 64,
+            IntTy::I128 => 128,
+        })
+    }
+
+    pub fn normalize(&self, target_width: u32) -> Self {
+        match self {
+            IntTy::Isize => match target_width {
+                16 => IntTy::I16,
+                32 => IntTy::I32,
+                64 => IntTy::I64,
+                _ => unreachable!(),
+            },
+            _ => *self,
+        }
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)]
+#[derive(Encodable, Decodable)]
+pub enum UintTy {
+    Usize,
+    U8,
+    U16,
+    U32,
+    U64,
+    U128,
+}
+
+impl UintTy {
+    pub fn name_str(&self) -> &'static str {
+        match *self {
+            UintTy::Usize => "usize",
+            UintTy::U8 => "u8",
+            UintTy::U16 => "u16",
+            UintTy::U32 => "u32",
+            UintTy::U64 => "u64",
+            UintTy::U128 => "u128",
+        }
+    }
+
+    pub fn bit_width(&self) -> Option<u64> {
+        Some(match *self {
+            UintTy::Usize => return None,
+            UintTy::U8 => 8,
+            UintTy::U16 => 16,
+            UintTy::U32 => 32,
+            UintTy::U64 => 64,
+            UintTy::U128 => 128,
+        })
+    }
+
+    pub fn normalize(&self, target_width: u32) -> Self {
+        match self {
+            UintTy::Usize => match target_width {
+                16 => UintTy::U16,
+                32 => UintTy::U32,
+                64 => UintTy::U64,
+                _ => unreachable!(),
+            },
+            _ => *self,
+        }
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Encodable, Decodable)]
+pub enum FloatTy {
+    F32,
+    F64,
+}
+
+impl FloatTy {
+    pub fn name_str(self) -> &'static str {
+        match self {
+            FloatTy::F32 => "f32",
+            FloatTy::F64 => "f64",
+        }
+    }
+
+    pub fn bit_width(self) -> u64 {
+        match self {
+            FloatTy::F32 => 32,
+            FloatTy::F64 => 64,
+        }
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum IntVarValue {
+    IntType(IntTy),
+    UintType(UintTy),
+}
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct FloatVarValue(pub FloatTy);
+
+/// A **ty**pe **v**ariable **ID**.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+pub struct TyVid {
+    pub index: u32,
+}
+
+/// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+pub struct IntVid {
+    pub index: u32,
+}
+
+/// An **float**ing-point (`f32` or `f64`) type **v**ariable **ID**.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+pub struct FloatVid {
+    pub index: u32,
+}
+
+/// A placeholder for a type that hasn't been inferred yet.
+///
+/// E.g., if we have an empty array (`[]`), then we create a fresh
+/// type variable for the element type since we won't know until it's
+/// used what the element type is supposed to be.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+pub enum InferTy {
+    /// A type variable.
+    TyVar(TyVid),
+    /// An integral type variable (`{integer}`).
+    ///
+    /// These are created when the compiler sees an integer literal like
+    /// `1` that could be several different types (`u8`, `i32`, `u32`, etc.).
+    /// We don't know until it's used what type it's supposed to be, so
+    /// we create a fresh type variable.
+    IntVar(IntVid),
+    /// A floating-point type variable (`{float}`).
+    ///
+    /// These are created when the compiler sees an float literal like
+    /// `1.0` that could be either an `f32` or an `f64`.
+    /// We don't know until it's used what type it's supposed to be, so
+    /// we create a fresh type variable.
+    FloatVar(FloatVid),
+
+    /// A [`FreshTy`][Self::FreshTy] is one that is generated as a replacement
+    /// for an unbound type variable. This is convenient for caching etc. See
+    /// `rustc_infer::infer::freshen` for more details.
+    ///
+    /// Compare with [`TyVar`][Self::TyVar].
+    FreshTy(u32),
+    /// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`IntVar`][Self::IntVar].
+    FreshIntTy(u32),
+    /// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`FloatVar`][Self::FloatVar].
+    FreshFloatTy(u32),
+}
+
+/// Raw `TyVid` are used as the unification key for `sub_relations`;
+/// they carry no values.
+impl UnifyKey for TyVid {
+    type Value = ();
+    fn index(&self) -> u32 {
+        self.index
+    }
+    fn from_index(i: u32) -> TyVid {
+        TyVid { index: i }
+    }
+    fn tag() -> &'static str {
+        "TyVid"
+    }
+}
+
+impl EqUnifyValue for IntVarValue {}
+
+impl UnifyKey for IntVid {
+    type Value = Option<IntVarValue>;
+    fn index(&self) -> u32 {
+        self.index
+    }
+    fn from_index(i: u32) -> IntVid {
+        IntVid { index: i }
+    }
+    fn tag() -> &'static str {
+        "IntVid"
+    }
+}
+
+impl EqUnifyValue for FloatVarValue {}
+
+impl UnifyKey for FloatVid {
+    type Value = Option<FloatVarValue>;
+    fn index(&self) -> u32 {
+        self.index
+    }
+    fn from_index(i: u32) -> FloatVid {
+        FloatVid { index: i }
+    }
+    fn tag() -> &'static str {
+        "FloatVid"
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Decodable, Encodable)]
+pub enum Variance {
+    Covariant,     // T<A> <: T<B> iff A <: B -- e.g., function return type
+    Invariant,     // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
+    Contravariant, // T<A> <: T<B> iff B <: A -- e.g., function param type
+    Bivariant,     // T<A> <: T<B>            -- e.g., unused type parameter
+}
+
+impl Variance {
+    /// `a.xform(b)` combines the variance of a context with the
+    /// variance of a type with the following meaning. If we are in a
+    /// context with variance `a`, and we encounter a type argument in
+    /// a position with variance `b`, then `a.xform(b)` is the new
+    /// variance with which the argument appears.
+    ///
+    /// Example 1:
+    ///
+    ///     *mut Vec<i32>
+    ///
+    /// Here, the "ambient" variance starts as covariant. `*mut T` is
+    /// invariant with respect to `T`, so the variance in which the
+    /// `Vec<i32>` appears is `Covariant.xform(Invariant)`, which
+    /// yields `Invariant`. Now, the type `Vec<T>` is covariant with
+    /// respect to its type argument `T`, and hence the variance of
+    /// the `i32` here is `Invariant.xform(Covariant)`, which results
+    /// (again) in `Invariant`.
+    ///
+    /// Example 2:
+    ///
+    ///     fn(*const Vec<i32>, *mut Vec<i32)
+    ///
+    /// The ambient variance is covariant. A `fn` type is
+    /// contravariant with respect to its parameters, so the variance
+    /// within which both pointer types appear is
+    /// `Covariant.xform(Contravariant)`, or `Contravariant`. `*const
+    /// T` is covariant with respect to `T`, so the variance within
+    /// which the first `Vec<i32>` appears is
+    /// `Contravariant.xform(Covariant)` or `Contravariant`. The same
+    /// is true for its `i32` argument. In the `*mut T` case, the
+    /// variance of `Vec<i32>` is `Contravariant.xform(Invariant)`,
+    /// and hence the outermost type is `Invariant` with respect to
+    /// `Vec<i32>` (and its `i32` argument).
+    ///
+    /// Source: Figure 1 of "Taming the Wildcards:
+    /// Combining Definition- and Use-Site Variance" published in PLDI'11.
+    pub fn xform(self, v: Variance) -> Variance {
+        match (self, v) {
+            // Figure 1, column 1.
+            (Variance::Covariant, Variance::Covariant) => Variance::Covariant,
+            (Variance::Covariant, Variance::Contravariant) => Variance::Contravariant,
+            (Variance::Covariant, Variance::Invariant) => Variance::Invariant,
+            (Variance::Covariant, Variance::Bivariant) => Variance::Bivariant,
+
+            // Figure 1, column 2.
+            (Variance::Contravariant, Variance::Covariant) => Variance::Contravariant,
+            (Variance::Contravariant, Variance::Contravariant) => Variance::Covariant,
+            (Variance::Contravariant, Variance::Invariant) => Variance::Invariant,
+            (Variance::Contravariant, Variance::Bivariant) => Variance::Bivariant,
+
+            // Figure 1, column 3.
+            (Variance::Invariant, _) => Variance::Invariant,
+
+            // Figure 1, column 4.
+            (Variance::Bivariant, _) => Variance::Bivariant,
+        }
+    }
+}
+
 impl<CTX> HashStable<CTX> for DebruijnIndex {
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         self.as_u32().hash_stable(ctx, hasher);
     }
 }
+
+impl<CTX> HashStable<CTX> for IntTy {
+    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        discriminant(self).hash_stable(ctx, hasher);
+    }
+}
+
+impl<CTX> HashStable<CTX> for UintTy {
+    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        discriminant(self).hash_stable(ctx, hasher);
+    }
+}
+
+impl<CTX> HashStable<CTX> for FloatTy {
+    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        discriminant(self).hash_stable(ctx, hasher);
+    }
+}
+
+impl<CTX> HashStable<CTX> for InferTy {
+    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        use InferTy::*;
+        match self {
+            TyVar(v) => v.index.hash_stable(ctx, hasher),
+            IntVar(v) => v.index.hash_stable(ctx, hasher),
+            FloatVar(v) => v.index.hash_stable(ctx, hasher),
+            FreshTy(v) | FreshIntTy(v) | FreshFloatTy(v) => v.hash_stable(ctx, hasher),
+        }
+    }
+}
+
+impl<CTX> HashStable<CTX> for Variance {
+    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        discriminant(self).hash_stable(ctx, hasher);
+    }
+}
+
+impl fmt::Debug for IntVarValue {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            IntVarValue::IntType(ref v) => v.fmt(f),
+            IntVarValue::UintType(ref v) => v.fmt(f),
+        }
+    }
+}
+
+impl fmt::Debug for FloatVarValue {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl fmt::Debug for TyVid {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "_#{}t", self.index)
+    }
+}
+
+impl fmt::Debug for IntVid {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "_#{}i", self.index)
+    }
+}
+
+impl fmt::Debug for FloatVid {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "_#{}f", self.index)
+    }
+}
+
+impl fmt::Debug for InferTy {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        use InferTy::*;
+        match *self {
+            TyVar(ref v) => v.fmt(f),
+            IntVar(ref v) => v.fmt(f),
+            FloatVar(ref v) => v.fmt(f),
+            FreshTy(v) => write!(f, "FreshTy({:?})", v),
+            FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
+            FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v),
+        }
+    }
+}
+
+impl fmt::Debug for Variance {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str(match *self {
+            Variance::Covariant => "+",
+            Variance::Contravariant => "-",
+            Variance::Invariant => "o",
+            Variance::Bivariant => "*",
+        })
+    }
+}
+
+impl fmt::Display for InferTy {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        use InferTy::*;
+        match *self {
+            TyVar(_) => write!(f, "_"),
+            IntVar(_) => write!(f, "{}", "{integer}"),
+            FloatVar(_) => write!(f, "{}", "{float}"),
+            FreshTy(v) => write!(f, "FreshTy({})", v),
+            FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
+            FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v),
+        }
+    }
+}
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 059f9b41068..437813ea41b 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -2059,9 +2059,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 match prim_ty {
                     hir::PrimTy::Bool => tcx.types.bool,
                     hir::PrimTy::Char => tcx.types.char,
-                    hir::PrimTy::Int(it) => tcx.mk_mach_int(it),
-                    hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(uit),
-                    hir::PrimTy::Float(ft) => tcx.mk_mach_float(ft),
+                    hir::PrimTy::Int(it) => tcx.mk_mach_int(ty::int_ty(it)),
+                    hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(ty::uint_ty(uit)),
+                    hir::PrimTy::Float(ft) => tcx.mk_mach_float(ty::float_ty(ft)),
                     hir::PrimTy::Str => tcx.types.str_,
                 }
             }
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 39dac0a909f..7924ffe8a6f 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -32,7 +32,6 @@ use super::FnCtxt;
 
 use crate::hir::def_id::DefId;
 use crate::type_error_struct;
-use rustc_ast as ast;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
@@ -660,7 +659,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             (_, Int(Bool)) => Err(CastError::CastToBool),
 
             // * -> Char
-            (Int(U(ast::UintTy::U8)), Int(Char)) => Ok(CastKind::U8CharCast), // u8-char-cast
+            (Int(U(ty::UintTy::U8)), Int(Char)) => Ok(CastKind::U8CharCast), // u8-char-cast
             (_, Int(Char)) => Err(CastError::CastToChar),
 
             // prim -> float,ptr
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index fb6f9c03352..3326be796ce 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -372,13 +372,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // in C but we just error out instead and require explicit casts.
                 let arg_ty = self.structurally_resolved_type(arg.span, arg_ty);
                 match arg_ty.kind() {
-                    ty::Float(ast::FloatTy::F32) => {
+                    ty::Float(ty::FloatTy::F32) => {
                         variadic_error(tcx.sess, arg.span, arg_ty, "c_double");
                     }
-                    ty::Int(ast::IntTy::I8 | ast::IntTy::I16) | ty::Bool => {
+                    ty::Int(ty::IntTy::I8 | ty::IntTy::I16) | ty::Bool => {
                         variadic_error(tcx.sess, arg.span, arg_ty, "c_int");
                     }
-                    ty::Uint(ast::UintTy::U8 | ast::UintTy::U16) => {
+                    ty::Uint(ty::UintTy::U8 | ty::UintTy::U16) => {
                         variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
                     }
                     ty::FnDef(..) => {
@@ -407,8 +407,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             ast::LitKind::Byte(_) => tcx.types.u8,
             ast::LitKind::Char(_) => tcx.types.char,
-            ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t),
-            ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t),
+            ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(ty::int_ty(t)),
+            ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(ty::uint_ty(t)),
             ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
                 let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
                     ty::Int(_) | ty::Uint(_) => Some(ty),
@@ -419,7 +419,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 });
                 opt_ty.unwrap_or_else(|| self.next_int_var())
             }
-            ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t),
+            ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => {
+                tcx.mk_mach_float(ty::float_ty(t))
+            }
             ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => {
                 let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
                     ty::Float(_) => Some(ty),
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 8335239f804..158c214759d 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -8,7 +8,6 @@ use crate::errors::MethodCallOnUnknownType;
 use crate::hir::def::DefKind;
 use crate::hir::def_id::DefId;
 
-use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
@@ -662,30 +661,30 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             }
             ty::Int(i) => {
                 let lang_def_id = match i {
-                    ast::IntTy::I8 => lang_items.i8_impl(),
-                    ast::IntTy::I16 => lang_items.i16_impl(),
-                    ast::IntTy::I32 => lang_items.i32_impl(),
-                    ast::IntTy::I64 => lang_items.i64_impl(),
-                    ast::IntTy::I128 => lang_items.i128_impl(),
-                    ast::IntTy::Isize => lang_items.isize_impl(),
+                    ty::IntTy::I8 => lang_items.i8_impl(),
+                    ty::IntTy::I16 => lang_items.i16_impl(),
+                    ty::IntTy::I32 => lang_items.i32_impl(),
+                    ty::IntTy::I64 => lang_items.i64_impl(),
+                    ty::IntTy::I128 => lang_items.i128_impl(),
+                    ty::IntTy::Isize => lang_items.isize_impl(),
                 };
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::Uint(i) => {
                 let lang_def_id = match i {
-                    ast::UintTy::U8 => lang_items.u8_impl(),
-                    ast::UintTy::U16 => lang_items.u16_impl(),
-                    ast::UintTy::U32 => lang_items.u32_impl(),
-                    ast::UintTy::U64 => lang_items.u64_impl(),
-                    ast::UintTy::U128 => lang_items.u128_impl(),
-                    ast::UintTy::Usize => lang_items.usize_impl(),
+                    ty::UintTy::U8 => lang_items.u8_impl(),
+                    ty::UintTy::U16 => lang_items.u16_impl(),
+                    ty::UintTy::U32 => lang_items.u32_impl(),
+                    ty::UintTy::U64 => lang_items.u64_impl(),
+                    ty::UintTy::U128 => lang_items.u128_impl(),
+                    ty::UintTy::Usize => lang_items.usize_impl(),
                 };
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::Float(f) => {
                 let (lang_def_id1, lang_def_id2) = match f {
-                    ast::FloatTy::F32 => (lang_items.f32_impl(), lang_items.f32_runtime_impl()),
-                    ast::FloatTy::F64 => (lang_items.f64_impl(), lang_items.f64_runtime_impl()),
+                    ty::FloatTy::F32 => (lang_items.f32_impl(), lang_items.f32_runtime_impl()),
+                    ty::FloatTy::F64 => (lang_items.f64_impl(), lang_items.f64_runtime_impl()),
                 };
                 self.assemble_inherent_impl_for_primitive(lang_def_id1);
                 self.assemble_inherent_impl_for_primitive(lang_def_id2);
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 79234f076ac..1c1f7f7886f 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -1525,24 +1525,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 _ => return err,
             },
             [.., field] => {
-                // if last field has a trailing comma, use the comma
-                // as the span to avoid trailing comma in ultimate
-                // suggestion (Issue #78511)
-                let tail = field.span.shrink_to_hi().until(pat.span.shrink_to_hi());
-                let tail_through_comma = self.tcx.sess.source_map().span_through_char(tail, ',');
-                let sp = if tail_through_comma == tail {
-                    field.span.shrink_to_hi()
-                } else {
-                    tail_through_comma
-                };
-                (
-                    match pat.kind {
-                        PatKind::Struct(_, [_, ..], _) => ", ",
-                        _ => "",
-                    },
-                    "",
-                    sp,
-                )
+                // Account for last field having a trailing comma or parse recovery at the tail of
+                // the pattern to avoid invalid suggestion (#78511).
+                let tail = field.span.shrink_to_hi().with_hi(pat.span.hi());
+                match &pat.kind {
+                    PatKind::Struct(..) => (", ", " }", tail),
+                    _ => return err,
+                }
             }
         };
         err.span_suggestion(
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index feda35daa61..6b2cba62fa6 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -42,7 +42,7 @@ use rustc_infer::infer::UpvarRegion;
 use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, ProjectionKind};
 use rustc_middle::ty::{self, Ty, TyCtxt, UpvarSubsts};
 use rustc_span::sym;
-use rustc_span::{Span, Symbol};
+use rustc_span::{MultiSpan, Span, Symbol};
 
 /// Describe the relationship between the paths of two places
 /// eg:
@@ -135,7 +135,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                     let upvar_id = ty::UpvarId::new(var_hir_id, local_def_id);
                     let capture_kind = self.init_capture_kind(capture_clause, upvar_id, span);
-                    let info = ty::CaptureInfo { expr_id: None, capture_kind };
+                    let info = ty::CaptureInfo {
+                        capture_kind_expr_id: None,
+                        path_expr_id: None,
+                        capture_kind,
+                    };
 
                     capture_information.insert(place, info);
                 }
@@ -308,8 +312,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         if let Some(capture_kind) = upvar_capture_map.get(&upvar_id) {
                             // upvar_capture_map only stores the UpvarCapture (CaptureKind),
                             // so we create a fake capture info with no expression.
-                            let fake_capture_info =
-                                ty::CaptureInfo { expr_id: None, capture_kind: *capture_kind };
+                            let fake_capture_info = ty::CaptureInfo {
+                                capture_kind_expr_id: None,
+                                path_expr_id: None,
+                                capture_kind: *capture_kind,
+                            };
                             determine_capture_info(fake_capture_info, capture_info).capture_kind
                         } else {
                             capture_info.capture_kind
@@ -359,20 +366,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ///
     /// ```
     /// {
-    ///       Place(base: hir_id_s, projections: [], ....) -> (hir_id_L5, ByValue),
-    ///       Place(base: hir_id_p, projections: [Field(0, 0)], ...) -> (hir_id_L2, ByRef(MutBorrow))
-    ///       Place(base: hir_id_p, projections: [Field(1, 0)], ...) -> (hir_id_L3, ByRef(ImmutBorrow))
-    ///       Place(base: hir_id_p, projections: [], ...) -> (hir_id_L4, ByRef(ImmutBorrow))
+    ///       Place(base: hir_id_s, projections: [], ....) -> {
+    ///                                                            capture_kind_expr: hir_id_L5,
+    ///                                                            path_expr_id: hir_id_L5,
+    ///                                                            capture_kind: ByValue
+    ///                                                       },
+    ///       Place(base: hir_id_p, projections: [Field(0, 0)], ...) -> {
+    ///                                                                     capture_kind_expr: hir_id_L2,
+    ///                                                                     path_expr_id: hir_id_L2,
+    ///                                                                     capture_kind: ByValue
+    ///                                                                 },
+    ///       Place(base: hir_id_p, projections: [Field(1, 0)], ...) -> {
+    ///                                                                     capture_kind_expr: hir_id_L3,
+    ///                                                                     path_expr_id: hir_id_L3,
+    ///                                                                     capture_kind: ByValue
+    ///                                                                 },
+    ///       Place(base: hir_id_p, projections: [], ...) -> {
+    ///                                                          capture_kind_expr: hir_id_L4,
+    ///                                                          path_expr_id: hir_id_L4,
+    ///                                                          capture_kind: ByValue
+    ///                                                      },
     /// ```
     ///
     /// After the min capture analysis, we get:
     /// ```
     /// {
     ///       hir_id_s -> [
-    ///            Place(base: hir_id_s, projections: [], ....) -> (hir_id_L4, ByValue)
+    ///            Place(base: hir_id_s, projections: [], ....) -> {
+    ///                                                                capture_kind_expr: hir_id_L5,
+    ///                                                                path_expr_id: hir_id_L5,
+    ///                                                                capture_kind: ByValue
+    ///                                                            },
     ///       ],
     ///       hir_id_p -> [
-    ///            Place(base: hir_id_p, projections: [], ...) -> (hir_id_L2, ByRef(MutBorrow)),
+    ///            Place(base: hir_id_p, projections: [], ...) -> {
+    ///                                                               capture_kind_expr: hir_id_L2,
+    ///                                                               path_expr_id: hir_id_L4,
+    ///                                                               capture_kind: ByValue
+    ///                                                           },
     ///       ],
     /// ```
     fn compute_min_captures(
@@ -425,8 +456,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // current place is ancestor of possible_descendant
                     PlaceAncestryRelation::Ancestor => {
                         descendant_found = true;
+                        let backup_path_expr_id = updated_capture_info.path_expr_id;
+
                         updated_capture_info =
                             determine_capture_info(updated_capture_info, possible_descendant.info);
+
+                        // we need to keep the ancestor's `path_expr_id`
+                        updated_capture_info.path_expr_id = backup_path_expr_id;
                         false
                     }
 
@@ -441,9 +477,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // current place is descendant of possible_ancestor
                         PlaceAncestryRelation::Descendant => {
                             ancestor_found = true;
+                            let backup_path_expr_id = possible_ancestor.info.path_expr_id;
                             possible_ancestor.info =
                                 determine_capture_info(possible_ancestor.info, capture_info);
 
+                            // we need to keep the ancestor's `path_expr_id`
+                            possible_ancestor.info.path_expr_id = backup_path_expr_id;
+
                             // Only one ancestor of the current place will be in the list.
                             break;
                         }
@@ -518,7 +558,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let capture_str = construct_capture_info_string(self.tcx, place, capture_info);
                 let output_str = format!("Capturing {}", capture_str);
 
-                let span = capture_info.expr_id.map_or(closure_span, |e| self.tcx.hir().span(e));
+                let span =
+                    capture_info.path_expr_id.map_or(closure_span, |e| self.tcx.hir().span(e));
                 diag.span_note(span, &output_str);
             }
             diag.emit();
@@ -542,9 +583,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             construct_capture_info_string(self.tcx, place, capture_info);
                         let output_str = format!("Min Capture {}", capture_str);
 
-                        let span =
-                            capture_info.expr_id.map_or(closure_span, |e| self.tcx.hir().span(e));
-                        diag.span_note(span, &output_str);
+                        if capture.info.path_expr_id != capture.info.capture_kind_expr_id {
+                            let path_span = capture_info
+                                .path_expr_id
+                                .map_or(closure_span, |e| self.tcx.hir().span(e));
+                            let capture_kind_span = capture_info
+                                .capture_kind_expr_id
+                                .map_or(closure_span, |e| self.tcx.hir().span(e));
+
+                            let mut multi_span: MultiSpan =
+                                MultiSpan::from_spans(vec![path_span, capture_kind_span]);
+
+                            let capture_kind_label =
+                                construct_capture_kind_reason_string(self.tcx, place, capture_info);
+                            let path_label = construct_path_string(self.tcx, place);
+
+                            multi_span.push_span_label(path_span, path_label);
+                            multi_span.push_span_label(capture_kind_span, capture_kind_label);
+
+                            diag.span_note(multi_span, &output_str);
+                        } else {
+                            let span = capture_info
+                                .path_expr_id
+                                .map_or(closure_span, |e| self.tcx.hir().span(e));
+
+                            diag.span_note(span, &output_str);
+                        };
                     }
                 }
                 diag.emit();
@@ -642,7 +706,8 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
         );
 
         let capture_info = ty::CaptureInfo {
-            expr_id: Some(diag_expr_id),
+            capture_kind_expr_id: Some(diag_expr_id),
+            path_expr_id: Some(diag_expr_id),
             capture_kind: ty::UpvarCapture::ByValue(Some(usage_span)),
         };
 
@@ -762,7 +827,8 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
             let new_upvar_borrow = ty::UpvarBorrow { kind, region: curr_upvar_borrow.region };
 
             let capture_info = ty::CaptureInfo {
-                expr_id: Some(diag_expr_id),
+                capture_kind_expr_id: Some(diag_expr_id),
+                path_expr_id: Some(diag_expr_id),
                 capture_kind: ty::UpvarCapture::ByRef(new_upvar_borrow),
             };
             let updated_info = determine_capture_info(curr_capture_info, capture_info);
@@ -824,7 +890,11 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
                 self.fcx.init_capture_kind(self.capture_clause, upvar_id, self.closure_span);
 
             let expr_id = Some(diag_expr_id);
-            let capture_info = ty::CaptureInfo { expr_id, capture_kind };
+            let capture_info = ty::CaptureInfo {
+                capture_kind_expr_id: expr_id,
+                path_expr_id: expr_id,
+                capture_kind,
+            };
 
             debug!("Capturing new place {:?}, capture_info={:?}", place_with_id, capture_info);
 
@@ -890,11 +960,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
     }
 }
 
-fn construct_capture_info_string(
-    tcx: TyCtxt<'_>,
-    place: &Place<'tcx>,
-    capture_info: &ty::CaptureInfo<'tcx>,
-) -> String {
+fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
     let variable_name = match place.base {
         PlaceBase::Upvar(upvar_id) => var_name(tcx, upvar_id.var_path.hir_id).to_string(),
         _ => bug!("Capture_information should only contain upvars"),
@@ -914,11 +980,42 @@ fn construct_capture_info_string(
         projections_str.push_str(proj.as_str());
     }
 
+    format!("{}[{}]", variable_name, projections_str)
+}
+
+fn construct_capture_kind_reason_string(
+    tcx: TyCtxt<'_>,
+    place: &Place<'tcx>,
+    capture_info: &ty::CaptureInfo<'tcx>,
+) -> String {
+    let place_str = construct_place_string(tcx, &place);
+
     let capture_kind_str = match capture_info.capture_kind {
         ty::UpvarCapture::ByValue(_) => "ByValue".into(),
         ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind),
     };
-    format!("{}[{}] -> {}", variable_name, projections_str, capture_kind_str)
+
+    format!("{} captured as {} here", place_str, capture_kind_str)
+}
+
+fn construct_path_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
+    let place_str = construct_place_string(tcx, &place);
+
+    format!("{} used here", place_str)
+}
+
+fn construct_capture_info_string(
+    tcx: TyCtxt<'_>,
+    place: &Place<'tcx>,
+    capture_info: &ty::CaptureInfo<'tcx>,
+) -> String {
+    let place_str = construct_place_string(tcx, &place);
+
+    let capture_kind_str = match capture_info.capture_kind {
+        ty::UpvarCapture::ByValue(_) => "ByValue".into(),
+        ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind),
+    };
+    format!("{} -> {}", place_str, capture_kind_str)
 }
 
 fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol {
@@ -930,7 +1027,9 @@ fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol {
 /// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way)
 ///
 /// If both `CaptureKind`s are considered equivalent, then the CaptureInfo is selected based
-/// on the `CaptureInfo` containing an associated expression id.
+/// on the `CaptureInfo` containing an associated `capture_kind_expr_id`.
+///
+/// It is the caller's duty to figure out which path_expr_id to use.
 ///
 /// If both the CaptureKind and Expression are considered to be equivalent,
 /// then `CaptureInfo` A is preferred. This can be useful in cases where we want to priortize
@@ -981,7 +1080,7 @@ fn determine_capture_info(
     };
 
     if eq_capture_kind {
-        match (capture_info_a.expr_id, capture_info_b.expr_id) {
+        match (capture_info_a.capture_kind_expr_id, capture_info_b.capture_kind_expr_id) {
             (Some(_), _) | (None, None) => capture_info_a,
             (None, Some(_)) => capture_info_b,
         }
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index 9e6bf5ce52d..b6d740a4fdb 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -348,7 +348,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                 let min_list_wb = min_list
                     .iter()
                     .map(|captured_place| {
-                        let locatable = captured_place.info.expr_id.unwrap_or(
+                        let locatable = captured_place.info.path_expr_id.unwrap_or(
                             self.tcx().hir().local_def_id_to_hir_id(closure_def_id.expect_local()),
                         );
 
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
index 6b6c66932c8..8a500852a03 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
@@ -13,7 +13,6 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_middle::ty::{self, CrateInherentImpls, TyCtxt};
 
-use rustc_ast as ast;
 use rustc_span::Span;
 
 /// On-demand query: yields a map containing all types mapped to their inherent impls.
@@ -178,7 +177,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     assoc_items,
                 );
             }
-            ty::Int(ast::IntTy::I8) => {
+            ty::Int(ty::IntTy::I8) => {
                 self.check_primitive_impl(
                     def_id,
                     lang_items.i8_impl(),
@@ -189,7 +188,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     assoc_items,
                 );
             }
-            ty::Int(ast::IntTy::I16) => {
+            ty::Int(ty::IntTy::I16) => {
                 self.check_primitive_impl(
                     def_id,
                     lang_items.i16_impl(),
@@ -200,7 +199,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     assoc_items,
                 );
             }
-            ty::Int(ast::IntTy::I32) => {
+            ty::Int(ty::IntTy::I32) => {
                 self.check_primitive_impl(
                     def_id,
                     lang_items.i32_impl(),
@@ -211,7 +210,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     assoc_items,
                 );
             }
-            ty::Int(ast::IntTy::I64) => {
+            ty::Int(ty::IntTy::I64) => {
                 self.check_primitive_impl(
                     def_id,
                     lang_items.i64_impl(),
@@ -222,7 +221,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     assoc_items,
                 );
             }
-            ty::Int(ast::IntTy::I128) => {
+            ty::Int(ty::IntTy::I128) => {
                 self.check_primitive_impl(
                     def_id,
                     lang_items.i128_impl(),
@@ -233,7 +232,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     assoc_items,
                 );
             }
-            ty::Int(ast::IntTy::Isize) => {
+            ty::Int(ty::IntTy::Isize) => {
                 self.check_primitive_impl(
                     def_id,
                     lang_items.isize_impl(),
@@ -244,7 +243,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     assoc_items,
                 );
             }
-            ty::Uint(ast::UintTy::U8) => {
+            ty::Uint(ty::UintTy::U8) => {
                 self.check_primitive_impl(
                     def_id,
                     lang_items.u8_impl(),
@@ -255,7 +254,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     assoc_items,
                 );
             }
-            ty::Uint(ast::UintTy::U16) => {
+            ty::Uint(ty::UintTy::U16) => {
                 self.check_primitive_impl(
                     def_id,
                     lang_items.u16_impl(),
@@ -266,7 +265,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     assoc_items,
                 );
             }
-            ty::Uint(ast::UintTy::U32) => {
+            ty::Uint(ty::UintTy::U32) => {
                 self.check_primitive_impl(
                     def_id,
                     lang_items.u32_impl(),
@@ -277,7 +276,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     assoc_items,
                 );
             }
-            ty::Uint(ast::UintTy::U64) => {
+            ty::Uint(ty::UintTy::U64) => {
                 self.check_primitive_impl(
                     def_id,
                     lang_items.u64_impl(),
@@ -288,7 +287,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     assoc_items,
                 );
             }
-            ty::Uint(ast::UintTy::U128) => {
+            ty::Uint(ty::UintTy::U128) => {
                 self.check_primitive_impl(
                     def_id,
                     lang_items.u128_impl(),
@@ -299,7 +298,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     assoc_items,
                 );
             }
-            ty::Uint(ast::UintTy::Usize) => {
+            ty::Uint(ty::UintTy::Usize) => {
                 self.check_primitive_impl(
                     def_id,
                     lang_items.usize_impl(),
@@ -310,7 +309,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     assoc_items,
                 );
             }
-            ty::Float(ast::FloatTy::F32) => {
+            ty::Float(ty::FloatTy::F32) => {
                 self.check_primitive_impl(
                     def_id,
                     lang_items.f32_impl(),
@@ -321,7 +320,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     assoc_items,
                 );
             }
-            ty::Float(ast::FloatTy::F64) => {
+            ty::Float(ty::FloatTy::F64) => {
                 self.check_primitive_impl(
                     def_id,
                     lang_items.f64_impl(),
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index d589989511d..b1d98d75196 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -50,8 +50,6 @@ use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
 
-use std::ops::ControlFlow;
-
 mod item_bounds;
 mod type_of;
 
@@ -2080,38 +2078,6 @@ fn const_evaluatable_predicates_of<'tcx>(
                 ));
             }
         }
-
-        // Look into `TyAlias`.
-        fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
-            use ty::fold::{TypeFoldable, TypeVisitor};
-            struct TyAliasVisitor<'a, 'tcx> {
-                tcx: TyCtxt<'tcx>,
-                preds: &'a mut FxIndexSet<(ty::Predicate<'tcx>, Span)>,
-                span: Span,
-            }
-
-            impl<'a, 'tcx> TypeVisitor<'tcx> for TyAliasVisitor<'a, 'tcx> {
-                fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-                    if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val {
-                        self.preds.insert((
-                            ty::PredicateKind::ConstEvaluatable(def, substs).to_predicate(self.tcx),
-                            self.span,
-                        ));
-                    }
-                    ControlFlow::CONTINUE
-                }
-            }
-
-            if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind {
-                if let Res::Def(DefKind::TyAlias, def_id) = path.res {
-                    let mut visitor =
-                        TyAliasVisitor { tcx: self.tcx, preds: &mut self.preds, span: path.span };
-                    self.tcx.type_of(def_id).visit_with(&mut visitor);
-                }
-            }
-
-            intravisit::walk_ty(self, ty)
-        }
     }
 
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index 24364c6954e..bd2c266d93d 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -630,7 +630,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                         PlaceBase::Local(*var_hir_id)
                     };
                     let place_with_id = PlaceWithHirId::new(
-                        capture_info.expr_id.unwrap_or(closure_expr.hir_id),
+                        capture_info.path_expr_id.unwrap_or(closure_expr.hir_id),
                         place.base_ty,
                         place_base,
                         place.projections.clone(),
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index 139863bbe7f..a6d3b5ef813 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -267,6 +267,7 @@ pub trait AsMut<T: ?Sized> {
 ///
 /// [`String`]: ../../std/string/struct.String.html
 /// [`Vec`]: ../../std/vec/struct.Vec.html
+#[rustc_diagnostic_item = "into_trait"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Into<T>: Sized {
     /// Performs the conversion.
@@ -382,6 +383,7 @@ pub trait From<T>: Sized {
 ///
 /// This suffers the same restrictions and reasoning as implementing
 /// [`Into`], see there for details.
+#[rustc_diagnostic_item = "try_into_trait"]
 #[stable(feature = "try_from", since = "1.34.0")]
 pub trait TryInto<T>: Sized {
     /// The type returned in the event of a conversion error.
@@ -462,6 +464,7 @@ pub trait TryInto<T>: Sized {
 ///
 /// [`try_from`]: TryFrom::try_from
 /// [`!`]: ../../std/primitive.never.html
+#[rustc_diagnostic_item = "try_from_trait"]
 #[stable(feature = "try_from", since = "1.34.0")]
 pub trait TryFrom<T>: Sized {
     /// The type returned in the event of a conversion error.
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 8bae3da1273..987371f50ec 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -410,7 +410,6 @@ impl<R: Seek> Seek for BufReader<R> {
     /// # Example
     ///
     /// ```no_run
-    /// #![feature(seek_convenience)]
     /// use std::{
     ///     io::{self, BufRead, BufReader, Seek},
     ///     fs::File,
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index c87a56586c6..db3b0e2628f 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -1671,7 +1671,7 @@ pub trait Seek {
     /// # Example
     ///
     /// ```no_run
-    /// #![feature(seek_convenience)]
+    /// #![feature(seek_stream_len)]
     /// use std::{
     ///     io::{self, Seek},
     ///     fs::File,
@@ -1685,7 +1685,7 @@ pub trait Seek {
     ///     Ok(())
     /// }
     /// ```
-    #[unstable(feature = "seek_convenience", issue = "59359")]
+    #[unstable(feature = "seek_stream_len", issue = "59359")]
     fn stream_len(&mut self) -> Result<u64> {
         let old_pos = self.stream_position()?;
         let len = self.seek(SeekFrom::End(0))?;
@@ -1706,7 +1706,6 @@ pub trait Seek {
     /// # Example
     ///
     /// ```no_run
-    /// #![feature(seek_convenience)]
     /// use std::{
     ///     io::{self, BufRead, BufReader, Seek},
     ///     fs::File,
@@ -1723,7 +1722,7 @@ pub trait Seek {
     ///     Ok(())
     /// }
     /// ```
-    #[unstable(feature = "seek_convenience", issue = "59359")]
+    #[stable(feature = "seek_convenience", since = "1.51.0")]
     fn stream_position(&mut self) -> Result<u64> {
         self.seek(SeekFrom::Current(0))
     }
diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs
index 465f3f8f994..598fb670bb4 100644
--- a/library/test/src/test_result.rs
+++ b/library/test/src/test_result.rs
@@ -63,7 +63,7 @@ pub fn calc_result<'a>(
                 ))
             }
         }
-        (&ShouldPanic::Yes, Ok(())) => {
+        (&ShouldPanic::Yes, Ok(())) | (&ShouldPanic::YesWithMessage(_), Ok(())) => {
             TestResult::TrFailedMsg("test did not panic as expected".to_string())
         }
         _ if desc.allow_fail => TestResult::TrAllowedFail,
diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs
index 74313cc4438..a629829b885 100644
--- a/library/test/src/tests.rs
+++ b/library/test/src/tests.rs
@@ -228,21 +228,30 @@ fn test_should_panic_non_string_message_type() {
 #[test]
 #[cfg(not(target_os = "emscripten"))]
 fn test_should_panic_but_succeeds() {
-    fn f() {}
-    let desc = TestDescAndFn {
-        desc: TestDesc {
-            name: StaticTestName("whatever"),
-            ignore: false,
-            should_panic: ShouldPanic::Yes,
-            allow_fail: false,
-            test_type: TestType::Unknown,
-        },
-        testfn: DynTestFn(Box::new(f)),
-    };
-    let (tx, rx) = channel();
-    run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
-    let result = rx.recv().unwrap().result;
-    assert_eq!(result, TrFailedMsg("test did not panic as expected".to_string()));
+    let should_panic_variants = [ShouldPanic::Yes, ShouldPanic::YesWithMessage("error message")];
+
+    for &should_panic in should_panic_variants.iter() {
+        fn f() {}
+        let desc = TestDescAndFn {
+            desc: TestDesc {
+                name: StaticTestName("whatever"),
+                ignore: false,
+                should_panic,
+                allow_fail: false,
+                test_type: TestType::Unknown,
+            },
+            testfn: DynTestFn(Box::new(f)),
+        };
+        let (tx, rx) = channel();
+        run_test(&TestOpts::new(), false, desc, RunStrategy::InProcess, tx, Concurrent::No);
+        let result = rx.recv().unwrap().result;
+        assert_eq!(
+            result,
+            TrFailedMsg("test did not panic as expected".to_string()),
+            "should_panic == {:?}",
+            should_panic
+        );
+    }
 }
 
 fn report_time_test_template(report_time: bool) -> Option<TestExecTime> {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 86bce8b8707..bebb746c92d 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -11,7 +11,6 @@ use std::{slice, vec};
 use rustc_ast::attr;
 use rustc_ast::util::comments::beautify_doc_string;
 use rustc_ast::{self as ast, AttrStyle};
-use rustc_ast::{FloatTy, IntTy, UintTy};
 use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_feature::UnstableFeatures;
@@ -21,7 +20,7 @@ use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::Mutability;
 use rustc_index::vec::IndexVec;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::Session;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::DUMMY_SP;
@@ -1456,6 +1455,7 @@ impl GetDefId for Type {
 
 impl PrimitiveType {
     crate fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
+        use ast::{FloatTy, IntTy, UintTy};
         match prim {
             hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
             hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
@@ -1690,6 +1690,41 @@ impl From<ast::FloatTy> for PrimitiveType {
     }
 }
 
+impl From<ty::IntTy> for PrimitiveType {
+    fn from(int_ty: ty::IntTy) -> PrimitiveType {
+        match int_ty {
+            ty::IntTy::Isize => PrimitiveType::Isize,
+            ty::IntTy::I8 => PrimitiveType::I8,
+            ty::IntTy::I16 => PrimitiveType::I16,
+            ty::IntTy::I32 => PrimitiveType::I32,
+            ty::IntTy::I64 => PrimitiveType::I64,
+            ty::IntTy::I128 => PrimitiveType::I128,
+        }
+    }
+}
+
+impl From<ty::UintTy> for PrimitiveType {
+    fn from(uint_ty: ty::UintTy) -> PrimitiveType {
+        match uint_ty {
+            ty::UintTy::Usize => PrimitiveType::Usize,
+            ty::UintTy::U8 => PrimitiveType::U8,
+            ty::UintTy::U16 => PrimitiveType::U16,
+            ty::UintTy::U32 => PrimitiveType::U32,
+            ty::UintTy::U64 => PrimitiveType::U64,
+            ty::UintTy::U128 => PrimitiveType::U128,
+        }
+    }
+}
+
+impl From<ty::FloatTy> for PrimitiveType {
+    fn from(float_ty: ty::FloatTy) -> PrimitiveType {
+        match float_ty {
+            ty::FloatTy::F32 => PrimitiveType::F32,
+            ty::FloatTy::F64 => PrimitiveType::F64,
+        }
+    }
+}
+
 impl From<hir::PrimTy> for PrimitiveType {
     fn from(prim_ty: hir::PrimTy) -> PrimitiveType {
         match prim_ty {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 869d48fc25e..50ec6e69fbd 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -487,12 +487,16 @@ crate fn get_auto_trait_and_blanket_impls(
     ty: Ty<'tcx>,
     param_env_def_id: DefId,
 ) -> impl Iterator<Item = Item> {
-    let auto_impls = cx.sess().time("get_auto_trait_impls", || {
-        AutoTraitFinder::new(cx).get_auto_trait_impls(ty, param_env_def_id)
-    });
-    let blanket_impls = cx.sess().time("get_blanket_impls", || {
-        BlanketImplFinder::new(cx).get_blanket_impls(ty, param_env_def_id)
-    });
+    let auto_impls = cx
+        .sess()
+        .prof
+        .generic_activity("get_auto_trait_impls")
+        .run(|| AutoTraitFinder::new(cx).get_auto_trait_impls(ty, param_env_def_id));
+    let blanket_impls = cx
+        .sess()
+        .prof
+        .generic_activity("get_blanket_impls")
+        .run(|| BlanketImplFinder::new(cx).get_blanket_impls(ty, param_env_def_id));
     auto_impls.into_iter().chain(blanket_impls)
 }
 
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index 53f08318524..7e613220f2d 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -91,6 +91,11 @@ function getThemePickerElement() {
     return document.getElementById("theme-picker");
 }
 
+// Returns the current URL without any query parameter or hash.
+function getNakedUrl() {
+    return window.location.href.split("?")[0].split("#")[0];
+}
+
 // Sets the focus on the search bar at the top of the page
 function focusSearchBar() {
     getSearchInput().focus();
@@ -252,7 +257,9 @@ function defocusSearchBar() {
             hideSearchResults(search);
             var hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1);
             if (browserSupportsHistoryApi()) {
-                history.replaceState(hash, "", "?search=#" + hash);
+                // `window.location.search`` contains all the query parameters, not just `search`.
+                history.replaceState(hash, "",
+                    getNakedUrl() + window.location.search + "#" + hash);
             }
             elem = document.getElementById(hash);
             if (elem) {
@@ -1810,10 +1817,12 @@ function defocusSearchBar() {
             // Because searching is incremental by character, only the most
             // recent search query is added to the browser history.
             if (browserSupportsHistoryApi()) {
+                var newURL = getNakedUrl() + "?search=" + encodeURIComponent(query.raw) +
+                    window.location.hash;
                 if (!history.state && !params.search) {
-                    history.pushState(query, "", "?search=" + encodeURIComponent(query.raw));
+                    history.pushState(query, "", newURL);
                 } else {
-                    history.replaceState(query, "", "?search=" + encodeURIComponent(query.raw));
+                    history.replaceState(query, "", newURL);
                 }
             }
 
@@ -1922,7 +1931,8 @@ function defocusSearchBar() {
                 clearInputTimeout();
                 if (search_input.value.length === 0) {
                     if (browserSupportsHistoryApi()) {
-                        history.replaceState("", window.currentCrate + " - Rust", "?search=");
+                        history.replaceState("", window.currentCrate + " - Rust",
+                            getNakedUrl() + window.location.hash);
                     }
                     hideSearchResults();
                 } else {
@@ -2779,9 +2789,9 @@ function defocusSearchBar() {
         if (search_input.value !== "" && hasClass(search, "hidden")) {
             showSearchResults(search);
             if (browserSupportsHistoryApi()) {
-                history.replaceState(search_input.value,
-                                     "",
-                                     "?search=" + encodeURIComponent(search_input.value));
+                var extra = "?search=" + encodeURIComponent(search_input.value);
+                history.replaceState(search_input.value, "",
+                    getNakedUrl() + extra + window.location.hash);
             }
             document.title = searchTitle;
         }
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 7b5e9e5905f..6ec6620681b 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -30,7 +30,7 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
 
     for &cnum in cx.tcx.crates().iter() {
         for &(did, _) in cx.tcx.all_trait_implementations(cnum).iter() {
-            cx.tcx.sess.time("build_extern_trait_impl", || {
+            cx.tcx.sess.prof.generic_activity("build_extern_trait_impl").run(|| {
                 inline::build_impl(cx, None, did, None, &mut new_items);
             });
         }
@@ -39,7 +39,7 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
     // Also try to inline primitive impls from other crates.
     for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() {
         if !def_id.is_local() {
-            cx.sess().time("build_primitive_trait_impl", || {
+            cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| {
                 inline::build_impl(cx, None, def_id, None, &mut new_items);
 
                 // FIXME(eddyb) is this `doc(hidden)` check needed?
@@ -59,7 +59,7 @@ crate fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
     for &trait_did in cx.tcx.all_traits(LOCAL_CRATE).iter() {
         for &impl_node in cx.tcx.hir().trait_impls(trait_did) {
             let impl_did = cx.tcx.hir().local_def_id(impl_node);
-            cx.tcx.sess.time("build_local_trait_impl", || {
+            cx.tcx.sess.prof.generic_activity("build_local_trait_impl").run(|| {
                 let mut extra_attrs = Vec::new();
                 let mut parent = cx.tcx.parent(impl_did.to_def_id());
                 while let Some(did) = parent {
@@ -177,13 +177,11 @@ impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> {
         if i.is_struct() || i.is_enum() || i.is_union() {
             // FIXME(eddyb) is this `doc(hidden)` check needed?
             if !self.cx.tcx.get_attrs(i.def_id).lists(sym::doc).has_word(sym::hidden) {
-                self.cx.sess().time("get_auto_trait_and_blanket_synthetic_impls", || {
-                    self.impls.extend(get_auto_trait_and_blanket_impls(
-                        self.cx,
-                        self.cx.tcx.type_of(i.def_id),
-                        i.def_id,
-                    ));
-                });
+                self.impls.extend(get_auto_trait_and_blanket_impls(
+                    self.cx,
+                    self.cx.tcx.type_of(i.def_id),
+                    i.def_id,
+                ));
             }
         }
 
diff --git a/src/test/ui/closures/2229_closure_analysis/capture-analysis-1.rs b/src/test/ui/closures/2229_closure_analysis/capture-analysis-1.rs
new file mode 100644
index 00000000000..4368c830e1c
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/capture-analysis-1.rs
@@ -0,0 +1,35 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+#![feature(rustc_attrs)]
+
+#[derive(Debug)]
+struct Point {
+    x: i32,
+    y: i32,
+}
+
+fn main() {
+    let p = Point { x: 10, y: 10 };
+    let q = Point { x: 10, y: 10 };
+
+    let c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+    //~^ First Pass analysis includes:
+    //~| Min Capture analysis includes:
+        println!("{:?}", p);
+        //~^ NOTE: Capturing p[] -> ImmBorrow
+        //~| NOTE: Min Capture p[] -> ImmBorrow
+        println!("{:?}", p.x);
+        //~^ NOTE: Capturing p[(0, 0)] -> ImmBorrow
+
+        println!("{:?}", q.x);
+        //~^ NOTE: Capturing q[(0, 0)] -> ImmBorrow
+        println!("{:?}", q);
+        //~^ NOTE: Capturing q[] -> ImmBorrow
+        //~| NOTE: Min Capture q[] -> ImmBorrow
+    };
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/capture-analysis-1.stderr b/src/test/ui/closures/2229_closure_analysis/capture-analysis-1.stderr
new file mode 100644
index 00000000000..09255343af0
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/capture-analysis-1.stderr
@@ -0,0 +1,77 @@
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/capture-analysis-1.rs:17:13
+   |
+LL |     let c = #[rustc_capture_analysis]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/capture-analysis-1.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error: First Pass analysis includes:
+  --> $DIR/capture-analysis-1.rs:20:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         println!("{:?}", p);
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing p[] -> ImmBorrow
+  --> $DIR/capture-analysis-1.rs:23:26
+   |
+LL |         println!("{:?}", p);
+   |                          ^
+note: Capturing p[(0, 0)] -> ImmBorrow
+  --> $DIR/capture-analysis-1.rs:26:26
+   |
+LL |         println!("{:?}", p.x);
+   |                          ^^^
+note: Capturing q[(0, 0)] -> ImmBorrow
+  --> $DIR/capture-analysis-1.rs:29:26
+   |
+LL |         println!("{:?}", q.x);
+   |                          ^^^
+note: Capturing q[] -> ImmBorrow
+  --> $DIR/capture-analysis-1.rs:31:26
+   |
+LL |         println!("{:?}", q);
+   |                          ^
+
+error: Min Capture analysis includes:
+  --> $DIR/capture-analysis-1.rs:20:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         println!("{:?}", p);
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture p[] -> ImmBorrow
+  --> $DIR/capture-analysis-1.rs:23:26
+   |
+LL |         println!("{:?}", p);
+   |                          ^
+note: Min Capture q[] -> ImmBorrow
+  --> $DIR/capture-analysis-1.rs:31:26
+   |
+LL |         println!("{:?}", q);
+   |                          ^
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/closures/2229_closure_analysis/capture-analysis-2.rs b/src/test/ui/closures/2229_closure_analysis/capture-analysis-2.rs
new file mode 100644
index 00000000000..ab7fce6a430
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/capture-analysis-2.rs
@@ -0,0 +1,30 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+#![feature(rustc_attrs)]
+
+#[derive(Debug)]
+struct Point {
+    x: String,
+    y: i32,
+}
+
+fn main() {
+    let mut p = Point { x: String::new(), y: 10 };
+
+    let c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+    //~^ First Pass analysis includes:
+    //~| Min Capture analysis includes:
+        let _x = p.x;
+        //~^ NOTE: Capturing p[(0, 0)] -> ByValue
+        //~| NOTE: p[] captured as ByValue here
+        println!("{:?}", p);
+        //~^ NOTE: Capturing p[] -> ImmBorrow
+        //~| NOTE: Min Capture p[] -> ByValue
+        //~| NOTE: p[] used here
+    };
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/capture-analysis-2.stderr b/src/test/ui/closures/2229_closure_analysis/capture-analysis-2.stderr
new file mode 100644
index 00000000000..0e48d6b300b
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/capture-analysis-2.stderr
@@ -0,0 +1,65 @@
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/capture-analysis-2.rs:16:13
+   |
+LL |     let c = #[rustc_capture_analysis]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/capture-analysis-2.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error: First Pass analysis includes:
+  --> $DIR/capture-analysis-2.rs:19:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let _x = p.x;
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing p[(0, 0)] -> ByValue
+  --> $DIR/capture-analysis-2.rs:22:18
+   |
+LL |         let _x = p.x;
+   |                  ^^^
+note: Capturing p[] -> ImmBorrow
+  --> $DIR/capture-analysis-2.rs:25:26
+   |
+LL |         println!("{:?}", p);
+   |                          ^
+
+error: Min Capture analysis includes:
+  --> $DIR/capture-analysis-2.rs:19:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let _x = p.x;
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture p[] -> ByValue
+  --> $DIR/capture-analysis-2.rs:22:18
+   |
+LL |         let _x = p.x;
+   |                  ^^^ p[] captured as ByValue here
+...
+LL |         println!("{:?}", p);
+   |                          ^ p[] used here
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/closures/2229_closure_analysis/capture-analysis-3.rs b/src/test/ui/closures/2229_closure_analysis/capture-analysis-3.rs
new file mode 100644
index 00000000000..817ade899e2
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/capture-analysis-3.rs
@@ -0,0 +1,35 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+#![feature(rustc_attrs)]
+
+#[derive(Debug)]
+struct Child {
+    c: String,
+    d: String,
+}
+
+#[derive(Debug)]
+struct Parent {
+    b: Child,
+}
+
+fn main() {
+    let mut a = Parent { b: Child {c: String::new(), d: String::new()} };
+
+    let c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+    //~^ First Pass analysis includes:
+    //~| Min Capture analysis includes:
+        let _x = a.b.c;
+        //~^ NOTE: Capturing a[(0, 0),(0, 0)] -> ByValue
+        //~| NOTE: a[(0, 0)] captured as ByValue here
+        println!("{:?}", a.b);
+        //~^ NOTE: Capturing a[(0, 0)] -> ImmBorrow
+        //~| NOTE: Min Capture a[(0, 0)] -> ByValue
+        //~| NOTE: a[(0, 0)] used here
+    };
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/capture-analysis-3.stderr b/src/test/ui/closures/2229_closure_analysis/capture-analysis-3.stderr
new file mode 100644
index 00000000000..263e9ca56eb
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/capture-analysis-3.stderr
@@ -0,0 +1,65 @@
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/capture-analysis-3.rs:21:13
+   |
+LL |     let c = #[rustc_capture_analysis]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/capture-analysis-3.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error: First Pass analysis includes:
+  --> $DIR/capture-analysis-3.rs:24:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let _x = a.b.c;
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing a[(0, 0),(0, 0)] -> ByValue
+  --> $DIR/capture-analysis-3.rs:27:18
+   |
+LL |         let _x = a.b.c;
+   |                  ^^^^^
+note: Capturing a[(0, 0)] -> ImmBorrow
+  --> $DIR/capture-analysis-3.rs:30:26
+   |
+LL |         println!("{:?}", a.b);
+   |                          ^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/capture-analysis-3.rs:24:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let _x = a.b.c;
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture a[(0, 0)] -> ByValue
+  --> $DIR/capture-analysis-3.rs:27:18
+   |
+LL |         let _x = a.b.c;
+   |                  ^^^^^ a[(0, 0)] captured as ByValue here
+...
+LL |         println!("{:?}", a.b);
+   |                          ^^^ a[(0, 0)] used here
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/closures/2229_closure_analysis/capture-analysis-4.rs b/src/test/ui/closures/2229_closure_analysis/capture-analysis-4.rs
new file mode 100644
index 00000000000..e8401299b30
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/capture-analysis-4.rs
@@ -0,0 +1,33 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+#![feature(rustc_attrs)]
+
+#[derive(Debug)]
+struct Child {
+    c: String,
+    d: String,
+}
+
+#[derive(Debug)]
+struct Parent {
+    b: Child,
+}
+
+fn main() {
+    let mut a = Parent { b: Child {c: String::new(), d: String::new()} };
+
+    let c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+    //~^ First Pass analysis includes:
+    //~| Min Capture analysis includes:
+        let _x = a.b;
+        //~^ NOTE: Capturing a[(0, 0)] -> ByValue
+        //~| NOTE: Min Capture a[(0, 0)] -> ByValue
+        println!("{:?}", a.b.c);
+        //~^ NOTE: Capturing a[(0, 0),(0, 0)] -> ImmBorrow
+    };
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/capture-analysis-4.stderr b/src/test/ui/closures/2229_closure_analysis/capture-analysis-4.stderr
new file mode 100644
index 00000000000..f4605c1d51b
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/capture-analysis-4.stderr
@@ -0,0 +1,62 @@
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/capture-analysis-4.rs:21:13
+   |
+LL |     let c = #[rustc_capture_analysis]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/capture-analysis-4.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error: First Pass analysis includes:
+  --> $DIR/capture-analysis-4.rs:24:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let _x = a.b;
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing a[(0, 0)] -> ByValue
+  --> $DIR/capture-analysis-4.rs:27:18
+   |
+LL |         let _x = a.b;
+   |                  ^^^
+note: Capturing a[(0, 0),(0, 0)] -> ImmBorrow
+  --> $DIR/capture-analysis-4.rs:30:26
+   |
+LL |         println!("{:?}", a.b.c);
+   |                          ^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/capture-analysis-4.rs:24:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let _x = a.b;
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture a[(0, 0)] -> ByValue
+  --> $DIR/capture-analysis-4.rs:27:18
+   |
+LL |         let _x = a.b;
+   |                  ^^^
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/closures/2229_closure_analysis/deep-multilevel-struct.rs b/src/test/ui/closures/2229_closure_analysis/deep-multilevel-struct.rs
new file mode 100644
index 00000000000..f81866bb7e0
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/deep-multilevel-struct.rs
@@ -0,0 +1,52 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+#![feature(rustc_attrs)]
+#![allow(unused)]
+
+#[derive(Debug)]
+struct Point {
+    x: i32,
+    y: i32,
+}
+#[derive(Debug)]
+struct Line {
+    p: Point,
+    q: Point
+}
+#[derive(Debug)]
+struct Plane {
+    a: Line,
+    b: Line,
+}
+
+fn main() {
+    let mut p = Plane {
+        a: Line {
+            p: Point { x: 1,y: 2 },
+            q: Point { x: 3,y: 4 },
+        },
+        b: Line {
+            p: Point { x: 1,y: 2 },
+            q: Point { x: 3,y: 4 },
+        }
+    };
+
+    let c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+    //~^ ERROR: First Pass analysis includes:
+    //~| ERROR: Min Capture analysis includes:
+        let x = &p.a.p.x;
+        //~^ NOTE: Capturing p[(0, 0),(0, 0),(0, 0)] -> ImmBorrow
+        p.b.q.y = 9;
+        //~^ NOTE: Capturing p[(1, 0),(1, 0),(1, 0)] -> MutBorrow
+        //~| NOTE: p[] captured as MutBorrow here
+        println!("{:?}", p);
+        //~^ NOTE: Capturing p[] -> ImmBorrow
+        //~| NOTE: Min Capture p[] -> MutBorrow
+        //~| NOTE: p[] used here
+    };
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/deep-multilevel-struct.stderr b/src/test/ui/closures/2229_closure_analysis/deep-multilevel-struct.stderr
new file mode 100644
index 00000000000..863f1009131
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/deep-multilevel-struct.stderr
@@ -0,0 +1,70 @@
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/deep-multilevel-struct.rs:36:13
+   |
+LL |     let c = #[rustc_capture_analysis]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/deep-multilevel-struct.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error: First Pass analysis includes:
+  --> $DIR/deep-multilevel-struct.rs:39:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let x = &p.a.p.x;
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing p[(0, 0),(0, 0),(0, 0)] -> ImmBorrow
+  --> $DIR/deep-multilevel-struct.rs:42:18
+   |
+LL |         let x = &p.a.p.x;
+   |                  ^^^^^^^
+note: Capturing p[(1, 0),(1, 0),(1, 0)] -> MutBorrow
+  --> $DIR/deep-multilevel-struct.rs:44:9
+   |
+LL |         p.b.q.y = 9;
+   |         ^^^^^^^
+note: Capturing p[] -> ImmBorrow
+  --> $DIR/deep-multilevel-struct.rs:47:26
+   |
+LL |         println!("{:?}", p);
+   |                          ^
+
+error: Min Capture analysis includes:
+  --> $DIR/deep-multilevel-struct.rs:39:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let x = &p.a.p.x;
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture p[] -> MutBorrow
+  --> $DIR/deep-multilevel-struct.rs:44:9
+   |
+LL |         p.b.q.y = 9;
+   |         ^^^^^^^ p[] captured as MutBorrow here
+...
+LL |         println!("{:?}", p);
+   |                          ^ p[] used here
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/closures/2229_closure_analysis/deep-multilevel-tuple.rs b/src/test/ui/closures/2229_closure_analysis/deep-multilevel-tuple.rs
new file mode 100644
index 00000000000..fb03a02efa0
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/deep-multilevel-tuple.rs
@@ -0,0 +1,27 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| NOTE: `#[warn(incomplete_features)]` on by default
+//~| NOTE: see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+#![feature(rustc_attrs)]
+#![allow(unused)]
+
+fn main() {
+    let mut t = (((1,2),(3,4)),((5,6),(7,8)));
+
+    let c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+    //~^ ERROR: First Pass analysis includes:
+    //~| ERROR: Min Capture analysis includes:
+        let x = &t.0.0.0;
+        //~^ NOTE: Capturing t[(0, 0),(0, 0),(0, 0)] -> ImmBorrow
+        t.1.1.1 = 9;
+        //~^ NOTE: Capturing t[(1, 0),(1, 0),(1, 0)] -> MutBorrow
+        //~| NOTE: t[] captured as MutBorrow here
+        println!("{:?}", t);
+        //~^ NOTE: Min Capture t[] -> MutBorrow
+        //~| NOTE: Capturing t[] -> ImmBorrow
+        //~| NOTE: t[] used here
+    };
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/deep-multilevel-tuple.stderr b/src/test/ui/closures/2229_closure_analysis/deep-multilevel-tuple.stderr
new file mode 100644
index 00000000000..252db444732
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/deep-multilevel-tuple.stderr
@@ -0,0 +1,70 @@
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/deep-multilevel-tuple.rs:11:13
+   |
+LL |     let c = #[rustc_capture_analysis]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/deep-multilevel-tuple.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error: First Pass analysis includes:
+  --> $DIR/deep-multilevel-tuple.rs:14:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let x = &t.0.0.0;
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing t[(0, 0),(0, 0),(0, 0)] -> ImmBorrow
+  --> $DIR/deep-multilevel-tuple.rs:17:18
+   |
+LL |         let x = &t.0.0.0;
+   |                  ^^^^^^^
+note: Capturing t[(1, 0),(1, 0),(1, 0)] -> MutBorrow
+  --> $DIR/deep-multilevel-tuple.rs:19:9
+   |
+LL |         t.1.1.1 = 9;
+   |         ^^^^^^^
+note: Capturing t[] -> ImmBorrow
+  --> $DIR/deep-multilevel-tuple.rs:22:26
+   |
+LL |         println!("{:?}", t);
+   |                          ^
+
+error: Min Capture analysis includes:
+  --> $DIR/deep-multilevel-tuple.rs:14:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let x = &t.0.0.0;
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture t[] -> MutBorrow
+  --> $DIR/deep-multilevel-tuple.rs:19:9
+   |
+LL |         t.1.1.1 = 9;
+   |         ^^^^^^^ t[] captured as MutBorrow here
+...
+LL |         println!("{:?}", t);
+   |                          ^ t[] used here
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.rs b/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.rs
index aaff3531e58..a6b5e12d2ed 100644
--- a/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.rs
+++ b/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.rs
@@ -32,9 +32,11 @@ fn main() {
     //~| ERROR: Min Capture analysis includes:
         p.x += 10;
         //~^ NOTE: Capturing p[(0, 0)] -> MutBorrow
-        //~| NOTE: Min Capture p[] -> MutBorrow
+        //~| NOTE: p[] captured as MutBorrow here
         println!("{:?}", p);
         //~^ NOTE: Capturing p[] -> ImmBorrow
+        //~| NOTE: Min Capture p[] -> MutBorrow
+        //~| NOTE: p[] used here
     };
 
     c();
diff --git a/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.stderr b/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.stderr
index 30d3d5f504e..cbbc8792199 100644
--- a/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/simple-struct-min-capture.stderr
@@ -55,7 +55,10 @@ note: Min Capture p[] -> MutBorrow
   --> $DIR/simple-struct-min-capture.rs:33:9
    |
 LL |         p.x += 10;
-   |         ^^^
+   |         ^^^ p[] captured as MutBorrow here
+...
+LL |         println!("{:?}", p);
+   |                          ^ p[] used here
 
 error: aborting due to 3 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/elaborate-trait-pred.rs b/src/test/ui/const-generics/const_evaluatable_checked/elaborate-trait-pred.rs
new file mode 100644
index 00000000000..4a4fd1e3311
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/elaborate-trait-pred.rs
@@ -0,0 +1,24 @@
+// run-pass
+// Test that we use the elaborated predicates from traits
+// to satisfy const evaluatable predicates.
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+use std::mem::size_of;
+
+trait Foo: Sized
+where
+    [(); size_of::<Self>()]: Sized,
+{
+}
+
+impl Foo for u64 {}
+impl Foo for u32 {}
+
+fn foo<T: Foo>() -> [u8; size_of::<T>()] {
+    [0; size_of::<T>()]
+}
+
+fn main() {
+    assert_eq!(foo::<u32>(), [0; 4]);
+    assert_eq!(foo::<u64>(), [0; 8]);
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/nested-abstract-consts-1.rs b/src/test/ui/const-generics/const_evaluatable_checked/nested-abstract-consts-1.rs
new file mode 100644
index 00000000000..0fe84c1cd2a
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/nested-abstract-consts-1.rs
@@ -0,0 +1,24 @@
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+fn callee<const M2: usize>() -> usize
+where
+    [u8; M2 + 1]: Sized,
+{
+    M2
+}
+
+fn caller<const N1: usize>() -> usize
+where
+    [u8; N1 + 1]: Sized,
+    [u8; (N1 + 1) + 1]: Sized,
+{
+    callee::<{ N1 + 1 }>()
+}
+
+fn main() {
+    assert_eq!(caller::<4>(), 5);
+}
+
+// Test that the ``(N1 + 1) + 1`` bound on ``caller`` satisfies the ``M2 + 1`` bound on ``callee``
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/nested-abstract-consts-2.rs b/src/test/ui/const-generics/const_evaluatable_checked/nested-abstract-consts-2.rs
new file mode 100644
index 00000000000..4f588238e23
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/nested-abstract-consts-2.rs
@@ -0,0 +1,35 @@
+// run-pass
+#![feature(const_evaluatable_checked, const_generics)]
+#![allow(incomplete_features)]
+
+struct Generic<const K: u64>;
+
+struct ConstU64<const K: u64>;
+
+impl<const K: u64> Generic<K>
+where
+    ConstU64<{ K - 1 }>: ,
+{
+    fn foo(self) -> u64 {
+        K
+    }
+}
+
+impl<const K: u64> Generic<K>
+where
+    ConstU64<{ K - 1 }>: ,
+    ConstU64<{ K + 1 }>: ,
+    ConstU64<{ K + 1 - 1 }>: ,
+{
+    fn bar(self) -> u64 {
+        let x: Generic<{ K + 1 }> = Generic;
+        x.foo()
+    }
+}
+
+fn main() {
+    assert_eq!((Generic::<10>).bar(), 11);
+}
+
+// Test that the ``ConstU64<{ K + 1 - 1}>`` bound on ``bar``'s impl block satisfies the
+// ``ConstU64<{K - 1}>`` bound on ``foo``'s impl block
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-1.rs b/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-1.rs
new file mode 100644
index 00000000000..1428f774b0d
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-1.rs
@@ -0,0 +1,35 @@
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+fn zero_init<const N: usize>() -> Substs1<N>
+where
+    [u8; N + 1]: ,
+{
+    Substs1([0; N + 1])
+}
+struct Substs1<const N: usize>([u8; N + 1])
+where
+    [(); N + 1]: ;
+
+fn substs2<const M: usize>() -> Substs1<{ M * 2 }>
+where
+    [(); { M * 2 } + 1]: ,
+{
+    zero_init::<{ M * 2 }>()
+}
+
+fn substs3<const L: usize>() -> Substs1<{ (L - 1) * 2 }>
+where
+    [(); (L - 1)]: ,
+    [(); (L - 1) * 2 + 1]: ,
+{
+    substs2::<{ L - 1 }>()
+}
+
+fn main() {
+    assert_eq!(substs3::<2>().0, [0; 3]);
+}
+
+// Test that the ``{ (L - 1) * 2 + 1 }`` bound on ``substs3`` satisfies the
+// ``{ N + 1 }`` bound on ``Substs1``
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-2.rs b/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-2.rs
new file mode 100644
index 00000000000..be8219a7446
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-2.rs
@@ -0,0 +1,29 @@
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features, unused_parens, unused_braces)]
+
+fn zero_init<const N: usize>() -> Substs1<{ (N) }>
+where
+    [u8; { (N) }]: ,
+{
+    Substs1([0; { (N) }])
+}
+
+struct Substs1<const N: usize>([u8; { (N) }])
+where
+    [(); { (N) }]: ;
+
+fn substs2<const M: usize>() -> Substs1<{ (M) }> {
+    zero_init::<{ (M) }>()
+}
+
+fn substs3<const L: usize>() -> Substs1<{ (L) }> {
+    substs2::<{ (L) }>()
+}
+
+fn main() {
+    assert_eq!(substs3::<2>().0, [0; 2]);
+}
+
+// Test that the implicit ``{ (L) }`` bound on ``substs3`` satisfies the
+// ``{ (N) }`` bound on ``Substs1``
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr
index c8549f101da..acf0a52ce5b 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr
@@ -1,9 +1,15 @@
 error[E0080]: evaluation of constant value failed
+  --> $DIR/simple_fail.rs:9:48
+   |
+LL | fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
+   |                                                ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
+
+error[E0080]: evaluation of constant value failed
   --> $DIR/simple_fail.rs:6:33
    |
 LL | type Arr<const N: usize> = [u8; N - 1];
    |                                 ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
index df54b4cbca5..fe5463f8acc 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
@@ -7,5 +7,14 @@ LL | type Arr<const N: usize> = [u8; N - 1];
    = help: const parameters may only be used as standalone arguments, i.e. `N`
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
-error: aborting due to previous error
+error: generic parameters may not be used in const operations
+  --> $DIR/simple_fail.rs:9:48
+   |
+LL | fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
+   |                                                ^ cannot perform const operation using `N`
+   |
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
index 3cbc077f4f1..c9535d04244 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
@@ -1,12 +1,14 @@
 // revisions: full min
 #![cfg_attr(full, feature(const_generics))]
-#![feature(const_evaluatable_checked)]
+#![cfg_attr(full, feature(const_evaluatable_checked))]
 #![allow(incomplete_features)]
 
 type Arr<const N: usize> = [u8; N - 1]; //[full]~ ERROR evaluation of constant
 //[min]~^ ERROR generic parameters may not be used in const operations
 
-fn test<const N: usize>() -> Arr<N> where Arr<N>: Sized {
+fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
+//[min]~^ ERROR generic parameters may not be used in const operations
+//[full]~^^ ERROR evaluation of constant
     todo!()
 }
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/ty-alias-substitution.rs b/src/test/ui/const-generics/const_evaluatable_checked/ty-alias-substitution.rs
new file mode 100644
index 00000000000..5c768a61be2
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/ty-alias-substitution.rs
@@ -0,0 +1,14 @@
+// check-pass
+// Test that we correctly substitute generic arguments for type aliases.
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+type Alias<T, const N: usize> = [T; N + 1];
+
+fn foo<const M: usize>() -> Alias<u32, M>  where [u8; M + 1]: Sized {
+    [0; M + 1]
+}
+
+fn main() {
+    foo::<0>();
+}
diff --git a/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr
index c0955ef8b06..8a83e145ea2 100644
--- a/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr
+++ b/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr
@@ -32,12 +32,12 @@ LL |     Struct { a, _ } = Struct { a: 1, b: 2 };
    |
 help: include the missing field in the pattern
    |
-LL |     Struct { a, b _ } = Struct { a: 1, b: 2 };
-   |               ^^^
+LL |     Struct { a, b } = Struct { a: 1, b: 2 };
+   |               ^^^^^
 help: if you don't care about this missing field, you can explicitly ignore it
    |
-LL |     Struct { a, .. _ } = Struct { a: 1, b: 2 };
-   |               ^^^^
+LL |     Struct { a, .. } = Struct { a: 1, b: 2 };
+   |               ^^^^^^
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/error-codes/E0027.stderr b/src/test/ui/error-codes/E0027.stderr
index 694bbc358fe..a3dd6910be4 100644
--- a/src/test/ui/error-codes/E0027.stderr
+++ b/src/test/ui/error-codes/E0027.stderr
@@ -7,11 +7,11 @@ LL |         Dog { age: x } => {}
 help: include the missing field in the pattern
    |
 LL |         Dog { age: x, name } => {}
-   |                     ^^^^^^
+   |                     ^^^^^^^^
 help: if you don't care about this missing field, you can explicitly ignore it
    |
 LL |         Dog { age: x, .. } => {}
-   |                     ^^^^
+   |                     ^^^^^^
 
 error[E0027]: pattern does not mention field `age`
   --> $DIR/E0027.rs:15:9
@@ -22,11 +22,11 @@ LL |         Dog { name: x, } => {}
 help: include the missing field in the pattern
    |
 LL |         Dog { name: x, age } => {}
-   |                      ^^^^^
+   |                      ^^^^^^^
 help: if you don't care about this missing field, you can explicitly ignore it
    |
 LL |         Dog { name: x, .. } => {}
-   |                      ^^^^
+   |                      ^^^^^^
 
 error[E0027]: pattern does not mention field `age`
   --> $DIR/E0027.rs:19:9
@@ -37,11 +37,11 @@ LL |         Dog { name: x  , } => {}
 help: include the missing field in the pattern
    |
 LL |         Dog { name: x, age } => {}
-   |                      ^^^^^
+   |                      ^^^^^^^
 help: if you don't care about this missing field, you can explicitly ignore it
    |
 LL |         Dog { name: x, .. } => {}
-   |                      ^^^^
+   |                      ^^^^^^
 
 error[E0027]: pattern does not mention fields `name`, `age`
   --> $DIR/E0027.rs:22:9
diff --git a/src/test/ui/structs/struct-pat-derived-error.stderr b/src/test/ui/structs/struct-pat-derived-error.stderr
index 921d060faa3..c1a95636d34 100644
--- a/src/test/ui/structs/struct-pat-derived-error.stderr
+++ b/src/test/ui/structs/struct-pat-derived-error.stderr
@@ -19,11 +19,11 @@ LL |         let A { x, y } = self.d;
 help: include the missing fields in the pattern
    |
 LL |         let A { x, y, b, c } = self.d;
-   |                     ^^^^^^
+   |                     ^^^^^^^^
 help: if you don't care about these missing fields, you can explicitly ignore them
    |
 LL |         let A { x, y, .. } = self.d;
-   |                     ^^^^
+   |                     ^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 783bc43c660bf39c1e562c8c429b32078ad3099
+Subproject c3abcfe8a75901c7c701557a728941e8fb19399
diff --git a/src/tools/clippy/clippy_lints/src/bytecount.rs b/src/tools/clippy/clippy_lints/src/bytecount.rs
index 38a0e27c4cf..ac9098a7584 100644
--- a/src/tools/clippy/clippy_lints/src/bytecount.rs
+++ b/src/tools/clippy/clippy_lints/src/bytecount.rs
@@ -2,11 +2,10 @@ use crate::utils::{
     contains_name, get_pat_name, match_type, paths, single_segment_path, snippet_with_applicability, span_lint_and_sugg,
 };
 use if_chain::if_chain;
-use rustc_ast::ast::UintTy;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
+use rustc_middle::ty::{self, UintTy};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
 use rustc_span::Symbol;
diff --git a/src/tools/clippy/clippy_lints/src/consts.rs b/src/tools/clippy/clippy_lints/src/consts.rs
index 166eadf86c1..640cffd24a7 100644
--- a/src/tools/clippy/clippy_lints/src/consts.rs
+++ b/src/tools/clippy/clippy_lints/src/consts.rs
@@ -2,14 +2,14 @@
 
 use crate::utils::{clip, sext, unsext};
 use if_chain::if_chain;
-use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
+use rustc_ast::ast::{self, LitFloatType, LitKind};
 use rustc_data_structures::sync::Lrc;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::ty::subst::{Subst, SubstsRef};
-use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
+use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Symbol;
 use std::cmp::Ordering::{self, Equal};
@@ -167,8 +167,8 @@ pub fn lit_to_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
         LitKind::Char(c) => Constant::Char(c),
         LitKind::Int(n, _) => Constant::Int(n),
         LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
-            FloatTy::F32 => Constant::F32(is.as_str().parse().unwrap()),
-            FloatTy::F64 => Constant::F64(is.as_str().parse().unwrap()),
+            ast::FloatTy::F32 => Constant::F32(is.as_str().parse().unwrap()),
+            ast::FloatTy::F64 => Constant::F64(is.as_str().parse().unwrap()),
         },
         LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.expect("type of float is known").kind() {
             ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()),
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index fb80f48a9cc..ae56a8ba5ab 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -3,10 +3,9 @@
 
 use crate::consts::{miri_to_const, Constant};
 use crate::utils::span_lint;
-use rustc_ast::ast::{IntTy, UintTy};
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
+use rustc_middle::ty::{self, IntTy, UintTy};
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use std::convert::TryFrom;
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index 9f389c8d2f9..527905e375d 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -1,7 +1,4 @@
-use crate::utils::paths::FROM_TRAIT;
-use crate::utils::{
-    is_expn_of, is_type_diagnostic_item, match_def_path, match_panic_def_id, method_chain_args, span_lint_and_then,
-};
+use crate::utils::{is_expn_of, is_type_diagnostic_item, match_panic_def_id, method_chain_args, span_lint_and_then};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -59,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for FallibleImplFrom {
         if_chain! {
             if let hir::ItemKind::Impl(impl_) = &item.kind;
             if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(impl_def_id);
-            if match_def_path(cx, impl_trait_ref.def_id, &FROM_TRAIT);
+            if cx.tcx.is_diagnostic_item(sym::from_trait, impl_trait_ref.def_id);
             then {
                 lint_impl_body(cx, item.span, impl_.items);
             }
diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs
index 1fe4461533b..be646cbe4d0 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -1,10 +1,10 @@
 use crate::utils::{numeric_literal, span_lint_and_sugg};
 use if_chain::if_chain;
-use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
+use rustc_ast::ast::{self, LitFloatType, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
+use rustc_middle::ty::{self, FloatTy};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use std::fmt;
 
@@ -75,8 +75,8 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
                 let digits = count_digits(&sym_str);
                 let max = max_digits(fty);
                 let type_suffix = match lit_float_ty {
-                    LitFloatType::Suffixed(FloatTy::F32) => Some("f32"),
-                    LitFloatType::Suffixed(FloatTy::F64) => Some("f64"),
+                    LitFloatType::Suffixed(ast::FloatTy::F32) => Some("f32"),
+                    LitFloatType::Suffixed(ast::FloatTy::F64) => Some("f64"),
                     LitFloatType::Unsuffixed => None
                 };
                 let (is_whole, mut float_str) = match fty {
diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
index ea986874291..40b236493a3 100644
--- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
+++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
@@ -3,7 +3,6 @@
 //! This lint is **warn** by default
 
 use crate::utils::{is_type_diagnostic_item, span_lint};
-use rustc_ast::ast;
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
@@ -77,8 +76,8 @@ impl<'tcx> LateLintPass<'tcx> for Mutex {
                         atomic_name
                     );
                     match *mutex_param.kind() {
-                        ty::Uint(t) if t != ast::UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
-                        ty::Int(t) if t != ast::IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
+                        ty::Uint(t) if t != ty::UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
+                        ty::Int(t) if t != ty::IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
                         _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg),
                     };
                 }
diff --git a/src/tools/clippy/clippy_lints/src/transmute.rs b/src/tools/clippy/clippy_lints/src/transmute.rs
index b0909f73177..d977cea4da5 100644
--- a/src/tools/clippy/clippy_lints/src/transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute.rs
@@ -443,7 +443,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
                             );
                         },
                     ),
-                    (ty::Int(ast::IntTy::I32) | ty::Uint(ast::UintTy::U32), &ty::Char) => {
+                    (ty::Int(ty::IntTy::I32) | ty::Uint(ty::UintTy::U32), &ty::Char) => {
                         span_lint_and_then(
                             cx,
                             TRANSMUTE_INT_TO_CHAR,
@@ -468,7 +468,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
                     (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) => {
                         if_chain! {
                             if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.kind(), &ty_to.kind());
-                            if let ty::Uint(ast::UintTy::U8) = slice_ty.kind();
+                            if let ty::Uint(ty::UintTy::U8) = slice_ty.kind();
                             if from_mutbl == to_mutbl;
                             then {
                                 let postfix = if *from_mutbl == Mutability::Mut {
@@ -536,7 +536,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
                             }
                         },
                     ),
-                    (ty::Int(ast::IntTy::I8) | ty::Uint(ast::UintTy::U8), ty::Bool) => {
+                    (ty::Int(ty::IntTy::I8) | ty::Uint(ty::UintTy::U8), ty::Bool) => {
                         span_lint_and_then(
                             cx,
                             TRANSMUTE_INT_TO_BOOL,
diff --git a/src/tools/clippy/clippy_lints/src/types.rs b/src/tools/clippy/clippy_lints/src/types.rs
index 3b5a83d2a0b..17cef0af3e9 100644
--- a/src/tools/clippy/clippy_lints/src/types.rs
+++ b/src/tools/clippy/clippy_lints/src/types.rs
@@ -5,7 +5,7 @@ use std::cmp::Ordering;
 use std::collections::BTreeMap;
 
 use if_chain::if_chain;
-use rustc_ast::{FloatTy, IntTy, LitFloatType, LitIntType, LitKind, UintTy};
+use rustc_ast::{LitFloatType, LitIntType, LitKind};
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor};
@@ -18,7 +18,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::TypeFoldable;
-use rustc_middle::ty::{self, InferTy, Ty, TyCtxt, TyS, TypeAndMut, TypeckResults};
+use rustc_middle::ty::{self, FloatTy, InferTy, IntTy, Ty, TyCtxt, TyS, TypeAndMut, TypeckResults, UintTy};
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
@@ -1106,9 +1106,7 @@ fn is_empty_block(expr: &Expr<'_>) -> bool {
         expr.kind,
         ExprKind::Block(
             Block {
-                stmts: &[],
-                expr: None,
-                ..
+                stmts: &[], expr: None, ..
             },
             _,
         )
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 9b262517a98..46b2b06d1a2 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -35,7 +35,6 @@ use std::mem;
 
 use if_chain::if_chain;
 use rustc_ast::ast::{self, Attribute, LitKind};
-use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -1224,27 +1223,27 @@ pub fn get_arg_name(pat: &Pat<'_>) -> Option<Symbol> {
     }
 }
 
-pub fn int_bits(tcx: TyCtxt<'_>, ity: ast::IntTy) -> u64 {
-    Integer::from_attr(&tcx, attr::IntType::SignedInt(ity)).size().bits()
+pub fn int_bits(tcx: TyCtxt<'_>, ity: ty::IntTy) -> u64 {
+    Integer::from_int_ty(&tcx, ity).size().bits()
 }
 
 #[allow(clippy::cast_possible_wrap)]
 /// Turn a constant int byte representation into an i128
-pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: ast::IntTy) -> i128 {
+pub fn sext(tcx: TyCtxt<'_>, u: u128, ity: ty::IntTy) -> i128 {
     let amt = 128 - int_bits(tcx, ity);
     ((u as i128) << amt) >> amt
 }
 
 #[allow(clippy::cast_sign_loss)]
 /// clip unused bytes
-pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: ast::IntTy) -> u128 {
+pub fn unsext(tcx: TyCtxt<'_>, u: i128, ity: ty::IntTy) -> u128 {
     let amt = 128 - int_bits(tcx, ity);
     ((u as u128) << amt) >> amt
 }
 
 /// clip unused bytes
-pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: ast::UintTy) -> u128 {
-    let bits = Integer::from_attr(&tcx, attr::IntType::UnsignedInt(ity)).size().bits();
+pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: ty::UintTy) -> u128 {
+    let bits = Integer::from_uint_ty(&tcx, ity).size().bits();
     let amt = 128 - bits;
     (u << amt) >> amt
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs
index c0b203b5388..432cc5b59f6 100644
--- a/src/tools/clippy/clippy_lints/src/utils/paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs
@@ -48,7 +48,6 @@ pub const FN_MUT: [&str; 3] = ["core", "ops", "FnMut"];
 pub const FN_ONCE: [&str; 3] = ["core", "ops", "FnOnce"];
 pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
 pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"];
-pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
 pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
 pub const HASH: [&str; 3] = ["core", "hash", "Hash"];
 pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"];
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 5424889a838..c8e76743231 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -174,7 +174,7 @@ impl fmt::Display for Debugger {
 /// Configuration for compiletest
 #[derive(Debug, Clone)]
 pub struct Config {
-    /// `true` to to overwrite stderr/stdout files instead of complaining about changes in output.
+    /// `true` to overwrite stderr/stdout files instead of complaining about changes in output.
     pub bless: bool,
 
     /// The library paths required for running the compiler.
diff --git a/src/tools/compiletest/src/util/tests.rs b/src/tools/compiletest/src/util/tests.rs
index 55bf659ba28..663027173ff 100644
--- a/src/tools/compiletest/src/util/tests.rs
+++ b/src/tools/compiletest/src/util/tests.rs
@@ -30,3 +30,22 @@ fn test_matches_os() {
     assert!(matches_os("nvptx64-nvidia-cuda", "cuda"));
     assert!(matches_os("x86_64-fortanix-unknown-sgx", "sgx"));
 }
+
+#[test]
+fn is_big_endian_test() {
+    assert!(!is_big_endian("no"));
+    assert!(is_big_endian("sparc-unknown-unknown"));
+}
+
+#[test]
+fn path_buf_with_extra_extension_test() {
+    assert_eq!(
+        PathBuf::from("foo.rs.stderr"),
+        PathBuf::from("foo.rs").with_extra_extension("stderr")
+    );
+    assert_eq!(
+        PathBuf::from("foo.rs.stderr"),
+        PathBuf::from("foo.rs").with_extra_extension(".stderr")
+    );
+    assert_eq!(PathBuf::from("foo.rs"), PathBuf::from("foo.rs").with_extra_extension(""));
+}