diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index 8a957a729fb68..004747d2a222a 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -1295,7 +1295,7 @@ fn generator_layout_and_saved_local_names(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
 ) -> (&'tcx GeneratorLayout<'tcx>, IndexVec<mir::GeneratorSavedLocal, Option<Symbol>>) {
-    let body = tcx.optimized_mir(def_id);
+    let body = tcx.optimized_mir(tcx.with_opt_param(def_id));
     let generator_layout = body.generator_layout.as_ref().unwrap();
     let mut generator_saved_local_names = IndexVec::from_elem(None, &generator_layout.field_tys);
 
diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs
index 217ad57ddc9c3..a2942c30d2bf1 100644
--- a/src/librustc_codegen_ssa/back/symbol_export.rs
+++ b/src/librustc_codegen_ssa/back/symbol_export.rs
@@ -249,9 +249,9 @@ fn exported_symbols_provider_local(
             }
 
             match *mono_item {
-                MonoItem::Fn(Instance { def: InstanceDef::Item(def_id), substs }) => {
+                MonoItem::Fn(Instance { def: InstanceDef::Item(def), substs }) => {
                     if substs.non_erasable_generics().next().is_some() {
-                        let symbol = ExportedSymbol::Generic(def_id, substs);
+                        let symbol = ExportedSymbol::Generic(def.did, substs);
                         symbols.push((symbol, SymbolExportLevel::Rust));
                     }
                 }
diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs
index 11ec62f96ed38..4943e279c7e05 100644
--- a/src/librustc_codegen_ssa/mir/constant.rs
+++ b/src/librustc_codegen_ssa/mir/constant.rs
@@ -25,10 +25,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         constant: &mir::Constant<'tcx>,
     ) -> Result<ConstValue<'tcx>, ErrorHandled> {
         match self.monomorphize(&constant.literal).val {
-            ty::ConstKind::Unevaluated(def_id, substs, promoted) => self
+            ty::ConstKind::Unevaluated(def, substs, promoted) => self
                 .cx
                 .tcx()
-                .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, promoted, None)
+                .const_eval_resolve(ty::ParamEnv::reveal_all(), def, substs, promoted, None)
                 .map_err(|err| {
                     if promoted.is_none() {
                         self.cx
diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs
index 8f8ce03d638c0..7b118baf014bb 100644
--- a/src/librustc_infer/infer/mod.rs
+++ b/src/librustc_infer/infer/mod.rs
@@ -1538,7 +1538,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn const_eval_resolve(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        def_id: DefId,
+        def: ty::WithOptParam<DefId>,
         substs: SubstsRef<'tcx>,
         promoted: Option<mir::Promoted>,
         span: Option<Span>,
@@ -1549,7 +1549,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         let (param_env, substs) = canonical.value;
         // The return value is the evaluated value which doesn't contain any reference to inference
         // variables, thus we don't need to substitute back the original values.
-        self.tcx.const_eval_resolve(param_env, def_id, substs, promoted, span)
+        self.tcx.const_eval_resolve(param_env, def, substs, promoted, span)
     }
 
     /// If `typ` is a type variable of some kind, resolve it one level
diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs
index 4ae7e417a8f67..233f478881cc8 100644
--- a/src/librustc_infer/traits/util.rs
+++ b/src/librustc_infer/traits/util.rs
@@ -40,8 +40,8 @@ pub fn anonymize_predicate<'tcx>(
             ty::PredicateKind::Subtype(tcx.anonymize_late_bound_regions(data))
         }
 
-        &ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
-            ty::PredicateKind::ConstEvaluatable(def_id, substs)
+        &ty::PredicateKind::ConstEvaluatable(def, substs) => {
+            ty::PredicateKind::ConstEvaluatable(def, substs)
         }
 
         ty::PredicateKind::ConstEquate(c1, c2) => ty::PredicateKind::ConstEquate(c1, c2),
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index e9a4119f4a333..a6e43266f1d05 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -848,7 +848,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
     });
 
     sess.time("MIR_borrow_checking", || {
-        tcx.par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id));
+        tcx.par_body_owners(|def_id| tcx.ensure().mir_borrowck(tcx.with_opt_param(def_id)));
     });
 
     sess.time("MIR_effect_checking", || {
@@ -856,7 +856,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
             mir::transform::check_unsafety::check_unsafety(tcx, def_id);
 
             if tcx.hir().body_const_context(def_id).is_some() {
-                tcx.ensure().mir_drops_elaborated_and_const_checked(def_id);
+                tcx.ensure().mir_drops_elaborated_and_const_checked(tcx.with_opt_param(def_id));
             }
         }
     });
diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
index 1b168bf01178c..b98e0de6f95cb 100644
--- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
+++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
@@ -75,6 +75,12 @@ impl IntoArgs for DefId {
     }
 }
 
+impl IntoArgs for ty::WithOptParam<DefId> {
+    fn into_args(self) -> (DefId, DefId) {
+        (self.did, self.param_did.unwrap_or(self.did))
+    }
+}
+
 impl IntoArgs for CrateNum {
     fn into_args(self) -> (DefId, DefId) {
         (self.as_def_id(), self.as_def_id())
diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs
index cdc8b5e90a642..dcad6933ee630 100644
--- a/src/librustc_metadata/rmeta/encoder.rs
+++ b/src/librustc_metadata/rmeta/encoder.rs
@@ -939,7 +939,8 @@ impl EncodeContext<'tcx> {
         record!(self.tables.kind[def_id] <- match impl_item.kind {
             ty::AssocKind::Const => {
                 if let hir::ImplItemKind::Const(_, body_id) = ast_item.kind {
-                    let qualifs = self.tcx.at(ast_item.span).mir_const_qualif(def_id);
+                    let tcx = self.tcx.at(ast_item.span);
+                    let qualifs = tcx.mir_const_qualif(tcx.with_opt_param(def_id));
 
                     EntryKind::AssocConst(
                         container,
@@ -1021,14 +1022,18 @@ impl EncodeContext<'tcx> {
     fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
         debug!("EntryBuilder::encode_mir({:?})", def_id);
         if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
-            record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
+            record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(
+                self.tcx.with_opt_param(def_id.to_def_id())
+            ));
         }
     }
 
     fn encode_promoted_mir(&mut self, def_id: LocalDefId) {
         debug!("EncodeContext::encode_promoted_mir({:?})", def_id);
         if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
-            record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
+            record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(
+                self.tcx.with_opt_param(def_id.to_def_id())
+            ));
         }
     }
 
@@ -1086,7 +1091,8 @@ impl EncodeContext<'tcx> {
             hir::ItemKind::Static(_, hir::Mutability::Mut, _) => EntryKind::MutStatic,
             hir::ItemKind::Static(_, hir::Mutability::Not, _) => EntryKind::ImmStatic,
             hir::ItemKind::Const(_, body_id) => {
-                let qualifs = self.tcx.at(item.span).mir_const_qualif(def_id);
+                let tcx = self.tcx.at(item.span);
+                let qualifs = tcx.mir_const_qualif(tcx.with_opt_param(def_id));
                 EntryKind::Const(
                     qualifs,
                     self.encode_rendered_const_for_body(body_id)
@@ -1328,7 +1334,7 @@ impl EncodeContext<'tcx> {
         // NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic,
         // including on the signature, which is inferred in `typeck_tables_of.
         let hir_id = self.tcx.hir().as_local_hir_id(def_id);
-        let ty = self.tcx.typeck_tables_of(def_id).node_type(hir_id);
+        let ty = self.tcx.typeck_tables_of(self.tcx.with_opt_param(def_id)).node_type(hir_id);
 
         record!(self.tables.kind[def_id.to_def_id()] <- match ty.kind {
             ty::Generator(..) => {
@@ -1357,7 +1363,7 @@ impl EncodeContext<'tcx> {
         let id = self.tcx.hir().as_local_hir_id(def_id);
         let body_id = self.tcx.hir().body_owned_by(id);
         let const_data = self.encode_rendered_const_for_body(body_id);
-        let qualifs = self.tcx.mir_const_qualif(def_id);
+        let qualifs = self.tcx.mir_const_qualif(self.tcx.with_opt_param(def_id.to_def_id()));
 
         record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::AnonConst(qualifs, const_data));
         record!(self.tables.visibility[def_id.to_def_id()] <- ty::Visibility::Public);
@@ -1744,8 +1750,9 @@ struct PrefetchVisitor<'tcx> {
 impl<'tcx> PrefetchVisitor<'tcx> {
     fn prefetch_mir(&self, def_id: LocalDefId) {
         if self.mir_keys.contains(&def_id) {
-            self.tcx.ensure().optimized_mir(def_id);
-            self.tcx.ensure().promoted_mir(def_id);
+            let def = self.tcx.with_opt_param(def_id).to_global();
+            self.tcx.ensure().optimized_mir(def);
+            self.tcx.ensure().promoted_mir(def);
         }
     }
 }
diff --git a/src/librustc_middle/dep_graph/dep_node.rs b/src/librustc_middle/dep_graph/dep_node.rs
index b14f17dee6060..b4447b6205c90 100644
--- a/src/librustc_middle/dep_graph/dep_node.rs
+++ b/src/librustc_middle/dep_graph/dep_node.rs
@@ -361,6 +361,44 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum {
     }
 }
 
+impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for ty::WithOptParam<DefId> {
+    #[inline]
+    fn can_reconstruct_query_key() -> bool {
+        true
+    }
+
+    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
+        tcx.def_path_hash(self.did).0
+    }
+
+    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
+        tcx.def_path_str(self.did)
+    }
+
+    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
+        dep_node.extract_def_id(tcx).map(|def_id| tcx.with_opt_param(def_id))
+    }
+}
+
+impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for ty::WithOptParam<LocalDefId> {
+    #[inline]
+    fn can_reconstruct_query_key() -> bool {
+        true
+    }
+
+    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
+        tcx.def_path_hash(self.did.to_def_id()).0
+    }
+
+    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
+        tcx.def_path_str(self.did.to_def_id())
+    }
+
+    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
+        dep_node.extract_def_id(tcx).map(|def_id| tcx.with_opt_param(def_id.expect_local()))
+    }
+}
+
 impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) {
     #[inline]
     fn can_reconstruct_query_key() -> bool {
diff --git a/src/librustc_middle/mir/interpret/queries.rs b/src/librustc_middle/mir/interpret/queries.rs
index a7953f0f900fb..bbaead535f6c7 100644
--- a/src/librustc_middle/mir/interpret/queries.rs
+++ b/src/librustc_middle/mir/interpret/queries.rs
@@ -34,12 +34,12 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn const_eval_resolve(
         self,
         param_env: ty::ParamEnv<'tcx>,
-        def_id: DefId,
+        def: ty::WithOptParam<DefId>,
         substs: SubstsRef<'tcx>,
         promoted: Option<mir::Promoted>,
         span: Option<Span>,
     ) -> ConstEvalResult<'tcx> {
-        match ty::Instance::resolve(self, param_env, def_id, substs) {
+        match ty::Instance::resolve_const_arg(self, param_env, def, substs) {
             Ok(Some(instance)) => {
                 let cid = GlobalId { instance, promoted };
                 self.const_eval_global_id(param_env, cid, span)
diff --git a/src/librustc_middle/mir/mono.rs b/src/librustc_middle/mir/mono.rs
index f1c1b962ab997..d86762f4827d2 100644
--- a/src/librustc_middle/mir/mono.rs
+++ b/src/librustc_middle/mir/mono.rs
@@ -346,8 +346,8 @@ impl<'tcx> CodegenUnit<'tcx> {
                             // instances into account. The others don't matter for
                             // the codegen tests and can even make item order
                             // unstable.
-                            InstanceDef::Item(def_id) => {
-                                def_id.as_local().map(|def_id| tcx.hir().as_local_hir_id(def_id))
+                            InstanceDef::Item(def) => {
+                                def.did.as_local().map(|def_id| tcx.hir().as_local_hir_id(def_id))
                             }
                             InstanceDef::VtableShim(..)
                             | InstanceDef::ReifyShim(..)
diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs
index 2f51b98085b4e..c4eefc8b1cfc7 100644
--- a/src/librustc_middle/query/mod.rs
+++ b/src/librustc_middle/query/mod.rs
@@ -89,6 +89,25 @@ rustc_queries! {
             desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
         }
 
+        /// Computes the `DefId` of the corresponding const parameter in case the `key` is a
+        /// const argument and returns `None` otherwise.
+        ///
+        /// ```rust
+        /// let a = foo::<7>();
+        /// //            ^ Calling `const_param_of` for this argument,
+        ///
+        /// fn foo<const N: usize>()
+        /// //           ^ returns this `DefId`.
+        ///
+        /// fn bar() {
+        /// // ^ While calling `const_param_of` for other bodies returns `None`.
+        /// }
+        /// ```
+        query const_param_of(key: DefId) -> Option<DefId> {
+            cache_on_disk_if { key.is_local() }
+            desc { |tcx| "computing the const parameter of `{}`", tcx.def_path_str(key) }
+        }
+
         /// Records the type of every item.
         query type_of(key: DefId) -> Ty<'tcx> {
             desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) }
@@ -185,50 +204,50 @@ rustc_queries! {
         /// Maps DefId's that have an associated `mir::Body` to the result
         /// of the MIR const-checking pass. This is the set of qualifs in
         /// the final value of a `const`.
-        query mir_const_qualif(key: DefId) -> mir::ConstQualifs {
-            desc { |tcx| "const checking `{}`", tcx.def_path_str(key) }
-            cache_on_disk_if { key.is_local() }
+        query mir_const_qualif(key: ty::WithOptParam<DefId>) -> mir::ConstQualifs {
+            desc { |tcx| "const checking `{}`", tcx.def_path_str(key.did) }
+            cache_on_disk_if { key.did.is_local() }
         }
 
         /// Fetch the MIR for a given `DefId` right after it's built - this includes
         /// unreachable code.
-        query mir_built(key: LocalDefId) -> Steal<mir::Body<'tcx>> {
+        query mir_built(key: ty::WithOptParam<LocalDefId>) -> Steal<mir::Body<'tcx>> {
             storage(ArenaCacheSelector<'tcx>)
-            desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key.to_def_id()) }
+            desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
         }
 
         /// Fetch the MIR for a given `DefId` up till the point where it is
         /// ready for const qualification.
         ///
         /// See the README for the `mir` module for details.
-        query mir_const(key: DefId) -> Steal<mir::Body<'tcx>> {
-            desc { |tcx| "processing MIR for `{}`", tcx.def_path_str(key)  }
+        query mir_const(key: ty::WithOptParam<DefId>) -> Steal<mir::Body<'tcx>> {
+            desc { |tcx| "processing MIR for `{}`", tcx.def_path_str(key.did) }
             storage(ArenaCacheSelector<'tcx>)
             no_hash
         }
 
-        query mir_drops_elaborated_and_const_checked(key: LocalDefId) -> Steal<mir::Body<'tcx>> {
+        query mir_drops_elaborated_and_const_checked(key: ty::WithOptParam<LocalDefId>) -> Steal<mir::Body<'tcx>> {
             storage(ArenaCacheSelector<'tcx>)
             no_hash
-            desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.to_def_id()) }
+            desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.did.to_def_id()) }
         }
 
-        query mir_validated(key: LocalDefId) ->
+        query mir_validated(key: ty::WithOptParam<LocalDefId>) ->
             (
                 Steal<mir::Body<'tcx>>,
                 Steal<IndexVec<mir::Promoted, mir::Body<'tcx>>>
             ) {
             storage(ArenaCacheSelector<'tcx>)
             no_hash
-            desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) }
+            desc { |tcx| "processing `{}`", tcx.def_path_str(key.did.to_def_id()) }
         }
 
         /// MIR after our optimization passes have run. This is MIR that is ready
         /// for codegen. This is also the only query that can fetch non-local MIR, at present.
-        query optimized_mir(key: DefId) -> mir::Body<'tcx> {
-            desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) }
+        query optimized_mir(key: ty::WithOptParam<DefId>) -> mir::Body<'tcx> {
+            desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key.did) }
             storage(ArenaCacheSelector<'tcx>)
-            cache_on_disk_if { key.is_local() }
+            cache_on_disk_if { key.did.is_local() }
         }
 
         query coverage_data(key: DefId) -> mir::CoverageData {
@@ -237,10 +256,10 @@ rustc_queries! {
             cache_on_disk_if { key.is_local() }
         }
 
-        query promoted_mir(key: DefId) -> IndexVec<mir::Promoted, mir::Body<'tcx>> {
-            desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) }
+        query promoted_mir(key: ty::WithOptParam<DefId>) -> IndexVec<mir::Promoted, mir::Body<'tcx>> {
+            desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key.did) }
             storage(ArenaCacheSelector<'tcx>)
-            cache_on_disk_if { key.is_local() }
+            cache_on_disk_if { key.did.is_local() }
         }
     }
 
@@ -450,8 +469,8 @@ rustc_queries! {
 
     TypeChecking {
         /// The result of unsafety-checking this `DefId`.
-        query unsafety_check_result(key: LocalDefId) -> mir::UnsafetyCheckResult {
-            desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+        query unsafety_check_result(key: ty::WithOptParam<LocalDefId>) -> mir::UnsafetyCheckResult {
+            desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.did.to_def_id()) }
             cache_on_disk_if { true }
             storage(ArenaCacheSelector<'tcx>)
         }
@@ -531,8 +550,8 @@ rustc_queries! {
             desc { "type-checking all item bodies" }
         }
 
-        query typeck_tables_of(key: LocalDefId) -> &'tcx ty::TypeckTables<'tcx> {
-            desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+        query typeck_tables_of(key: ty::WithOptParam<LocalDefId>) -> &'tcx ty::TypeckTables<'tcx> {
+            desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.did.to_def_id()) }
             cache_on_disk_if { true }
         }
         query diagnostic_only_typeck_tables_of(key: LocalDefId) -> &'tcx ty::TypeckTables<'tcx> {
@@ -568,11 +587,11 @@ rustc_queries! {
     BorrowChecking {
         /// Borrow-checks the function body. If this is a closure, returns
         /// additional requirements that the closure's creator must verify.
-        query mir_borrowck(key: LocalDefId) -> mir::BorrowCheckResult<'tcx> {
+        query mir_borrowck(key: ty::WithOptParam<LocalDefId>) -> mir::BorrowCheckResult<'tcx> {
             storage(ArenaCacheSelector<'tcx>)
-            desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+            desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.did.to_def_id()) }
             cache_on_disk_if(tcx, opt_result) {
-                tcx.is_closure(key.to_def_id())
+                tcx.is_closure(key.did.to_def_id())
                     || opt_result.map_or(false, |r| !r.concrete_opaque_types.is_empty())
             }
         }
@@ -1434,9 +1453,9 @@ rustc_queries! {
         ///    from `Ok(None)` to avoid misleading diagnostics when an error
         ///    has already been/will be emitted, for the original cause
         query resolve_instance(
-            key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>
+            key: ty::ParamEnvAnd<'tcx, (ty::WithOptParam<DefId>, SubstsRef<'tcx>)>
         ) -> Result<Option<ty::Instance<'tcx>>, ErrorReported> {
-            desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
+            desc { "resolving instance `{}`", ty::Instance::new(key.value.0.did, key.value.1) }
         }
     }
 }
diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs
index d628d6783d5b0..3cc33b422f58b 100644
--- a/src/librustc_middle/ty/instance.rs
+++ b/src/librustc_middle/ty/instance.rs
@@ -29,7 +29,7 @@ pub enum InstanceDef<'tcx> {
     /// - `fn` items
     /// - closures
     /// - generators
-    Item(DefId),
+    Item(ty::WithOptParam<DefId>),
 
     /// An intrinsic `fn` item (with `"rust-intrinsic"` or `"platform-intrinsic"` ABI).
     ///
@@ -160,8 +160,8 @@ impl<'tcx> Instance<'tcx> {
         self.substs.non_erasable_generics().next()?;
 
         match self.def {
-            InstanceDef::Item(def_id) => tcx
-                .upstream_monomorphizations_for(def_id)
+            InstanceDef::Item(def) => tcx
+                .upstream_monomorphizations_for(def.did)
                 .and_then(|monos| monos.get(&self.substs).cloned()),
             InstanceDef::DropGlue(_, Some(_)) => tcx.upstream_drop_glue_for(self.substs),
             _ => None,
@@ -173,8 +173,8 @@ impl<'tcx> InstanceDef<'tcx> {
     #[inline]
     pub fn def_id(&self) -> DefId {
         match *self {
-            InstanceDef::Item(def_id)
-            | InstanceDef::VtableShim(def_id)
+            InstanceDef::Item(def) => def.did,
+            InstanceDef::VtableShim(def_id)
             | InstanceDef::ReifyShim(def_id)
             | InstanceDef::FnPtrShim(def_id, _)
             | InstanceDef::Virtual(def_id, _)
@@ -185,6 +185,11 @@ impl<'tcx> InstanceDef<'tcx> {
         }
     }
 
+    #[inline]
+    pub fn with_opt_param(self) -> ty::WithOptParam<DefId> {
+        if let InstanceDef::Item(def) = self { def } else { ty::WithOptParam::dummy(self.def_id()) }
+    }
+
     #[inline]
     pub fn attrs(&self, tcx: TyCtxt<'tcx>) -> ty::Attributes<'tcx> {
         tcx.get_attrs(self.def_id())
@@ -198,7 +203,7 @@ impl<'tcx> InstanceDef<'tcx> {
     pub fn requires_inline(&self, tcx: TyCtxt<'tcx>) -> bool {
         use rustc_hir::definitions::DefPathData;
         let def_id = match *self {
-            ty::InstanceDef::Item(def_id) => def_id,
+            ty::InstanceDef::Item(def) => def.did,
             ty::InstanceDef::DropGlue(_, Some(_)) => return false,
             _ => return true,
         };
@@ -244,8 +249,8 @@ impl<'tcx> InstanceDef<'tcx> {
 
     pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool {
         match *self {
-            InstanceDef::Item(def_id) => {
-                tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
+            InstanceDef::Item(def) => {
+                tcx.codegen_fn_attrs(def.did).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
             }
             _ => false,
         }
@@ -276,14 +281,14 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
 }
 
 impl<'tcx> Instance<'tcx> {
-    pub fn new(def_id: DefId, substs: SubstsRef<'tcx>) -> Instance<'tcx> {
+    pub fn new(did: DefId, substs: SubstsRef<'tcx>) -> Instance<'tcx> {
         assert!(
             !substs.has_escaping_bound_vars(),
             "substs of instance {:?} not normalized for codegen: {:?}",
-            def_id,
+            did,
             substs
         );
-        Instance { def: InstanceDef::Item(def_id), substs }
+        Instance { def: InstanceDef::Item(ty::WithOptParam::dummy(did)), substs }
     }
 
     pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> {
@@ -295,6 +300,23 @@ impl<'tcx> Instance<'tcx> {
         self.def.def_id()
     }
 
+    /// Identical to `resolve`, but may also take an optional `param_def_id` for
+    /// generic const arguments.
+    pub fn resolve_const_arg(
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        def: ty::WithOptParam<DefId>,
+        substs: SubstsRef<'tcx>,
+    ) -> Result<Option<Instance<'tcx>>, ErrorReported> {
+        // HACK(eddyb) erase regions in `substs` first, so that `param_env.and(...)`
+        // below is more likely to ignore the bounds in scope (e.g. if the only
+        // generic parameters mentioned by `substs` were lifetime ones).
+        let substs = tcx.erase_regions(&substs);
+
+        // FIXME(eddyb) should this always use `param_env.with_reveal_all()`?
+        tcx.resolve_instance(tcx.erase_regions(&param_env.and((def, substs))))
+    }
+
     /// Resolves a `(def_id, substs)` pair to an (optional) instance -- most commonly,
     /// this is used to find the precise code that will run for a trait method invocation,
     /// if known.
@@ -333,7 +355,9 @@ impl<'tcx> Instance<'tcx> {
         let substs = tcx.erase_regions(&substs);
 
         // FIXME(eddyb) should this always use `param_env.with_reveal_all()`?
-        tcx.resolve_instance(tcx.erase_regions(&param_env.and((def_id, substs))))
+        tcx.resolve_instance(
+            tcx.erase_regions(&param_env.and((tcx.with_opt_param(def_id), substs))),
+        )
     }
 
     pub fn resolve_for_fn_ptr(
@@ -345,9 +369,9 @@ impl<'tcx> Instance<'tcx> {
         debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
         Instance::resolve(tcx, param_env, def_id, substs).ok().flatten().map(|mut resolved| {
             match resolved.def {
-                InstanceDef::Item(def_id) if resolved.def.requires_caller_location(tcx) => {
+                InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => {
                     debug!(" => fn pointer created for function with #[track_caller]");
-                    resolved.def = InstanceDef::ReifyShim(def_id);
+                    resolved.def = InstanceDef::ReifyShim(def.did);
                 }
                 InstanceDef::Virtual(def_id, _) => {
                     debug!(" => fn pointer created for virtual call");
diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs
index 6b7940ed7abcc..3a9c9249b7e90 100644
--- a/src/librustc_middle/ty/mod.rs
+++ b/src/librustc_middle/ty/mod.rs
@@ -14,6 +14,7 @@ use crate::mir::Body;
 use crate::mir::GeneratorLayout;
 use crate::traits::{self, Reveal};
 use crate::ty;
+use crate::ty::query::IntoQueryParam;
 use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
 use crate::ty::util::{Discr, IntTypeExt};
 use rustc_ast::ast;
@@ -1094,7 +1095,7 @@ pub enum PredicateKind<'tcx> {
     Subtype(PolySubtypePredicate<'tcx>),
 
     /// Constant initializer must evaluate successfully.
-    ConstEvaluatable(DefId, SubstsRef<'tcx>),
+    ConstEvaluatable(ty::WithOptParam<DefId>, SubstsRef<'tcx>),
 
     /// Constants must be equal. The first component is the const that is expected.
     ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>),
@@ -1208,8 +1209,8 @@ impl<'tcx> Predicate<'tcx> {
             &PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
                 PredicateKind::ClosureKind(closure_def_id, closure_substs.subst(tcx, substs), kind)
             }
-            &PredicateKind::ConstEvaluatable(def_id, const_substs) => {
-                PredicateKind::ConstEvaluatable(def_id, const_substs.subst(tcx, substs))
+            &PredicateKind::ConstEvaluatable(def, const_substs) => {
+                PredicateKind::ConstEvaluatable(def, const_substs.subst(tcx, substs))
             }
             PredicateKind::ConstEquate(c1, c2) => {
                 PredicateKind::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs))
@@ -1565,6 +1566,66 @@ pub type PlaceholderType = Placeholder<BoundVar>;
 
 pub type PlaceholderConst = Placeholder<BoundVar>;
 
+/// A `DefId` which is bundled with its corresponding generic parameter
+/// in case `did` is a const argument.
+///
+/// This is used to prevent cycle errors during typeck
+/// as `type_of(const_arg)` depends on `typeck_tables_of(owning_body)`
+/// which once again requires the type of its generic arguments.
+///
+/// Luckily we only need to deal with const arguments once we
+/// know their corresponding parameters. We (ab)use this by
+/// calling `type_of(param_did)` for these arguments.
+#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
+#[derive(PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Hash, HashStable)]
+pub struct WithOptParam<T> {
+    pub did: T,
+    /// The `DefId` of the corresponding generic paramter in case `did` is
+    /// a const argument.
+    ///
+    /// If `param_did` is `Some` it must be equal to `tcx.const_param_of`,
+    /// and may otherwise cause panics or problems.
+    pub param_did: Option<DefId>,
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+    #[inline(always)]
+    pub fn with_opt_param<T: IntoQueryParam<DefId> + Copy>(self, did: T) -> WithOptParam<T> {
+        WithOptParam { did, param_did: None }
+    }
+}
+
+impl<T: IntoQueryParam<DefId>> WithOptParam<T> {
+    /// Wraps the given `DefId` and sets `param_did` to none.
+    pub fn dummy(did: T) -> WithOptParam<T> {
+        WithOptParam { did, param_did: None }
+    }
+
+    pub fn ty_def_id(self) -> DefId {
+        self.param_did.unwrap_or(self.did.into_query_param())
+    }
+}
+
+impl WithOptParam<DefId> {
+    #[inline]
+    pub fn as_local(self) -> Option<WithOptParam<LocalDefId>> {
+        Some(WithOptParam { did: self.did.as_local()?, param_did: self.param_did })
+    }
+
+    #[inline]
+    pub fn expect_local(self) -> WithOptParam<LocalDefId> {
+        WithOptParam { did: self.did.expect_local(), param_did: self.param_did }
+    }
+}
+
+impl WithOptParam<LocalDefId> {
+    #[inline]
+    pub fn to_global(self) -> WithOptParam<DefId> {
+        WithOptParam { did: self.did.to_def_id(), param_did: self.param_did }
+    }
+}
+
 /// When type checking, we use the `ParamEnv` to track
 /// details about the set of where-clauses that are in scope at this
 /// particular point.
@@ -2566,7 +2627,7 @@ pub enum ImplOverlapKind {
 
 impl<'tcx> TyCtxt<'tcx> {
     pub fn body_tables(self, body: hir::BodyId) -> &'tcx TypeckTables<'tcx> {
-        self.typeck_tables_of(self.hir().body_owner_def_id(body))
+        self.typeck_tables_of(self.with_opt_param(self.hir().body_owner_def_id(body)))
     }
 
     /// Returns an iterator of the `DefId`s for all body-owners in this
@@ -2737,7 +2798,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
     pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
         match instance {
-            ty::InstanceDef::Item(did) => self.optimized_mir(did),
+            ty::InstanceDef::Item(def) => self.optimized_mir(def),
             ty::InstanceDef::VtableShim(..)
             | ty::InstanceDef::ReifyShim(..)
             | ty::InstanceDef::Intrinsic(..)
@@ -2769,7 +2830,7 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     pub fn generator_layout(self, def_id: DefId) -> &'tcx GeneratorLayout<'tcx> {
-        self.optimized_mir(def_id).generator_layout.as_ref().unwrap()
+        self.optimized_mir(self.with_opt_param(def_id)).generator_layout.as_ref().unwrap()
     }
 
     /// Given the `DefId` of an impl, returns the `DefId` of the trait it implements.
diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs
index 1a08639a533d5..930f7dbd24085 100644
--- a/src/librustc_middle/ty/print/pretty.rs
+++ b/src/librustc_middle/ty/print/pretty.rs
@@ -884,18 +884,18 @@ pub trait PrettyPrinter<'tcx>:
         }
 
         match ct.val {
-            ty::ConstKind::Unevaluated(did, substs, promoted) => {
+            ty::ConstKind::Unevaluated(def, substs, promoted) => {
                 if let Some(promoted) = promoted {
-                    p!(print_value_path(did, substs));
+                    p!(print_value_path(def.did, substs));
                     p!(write("::{:?}", promoted));
                 } else {
-                    match self.tcx().def_kind(did) {
+                    match self.tcx().def_kind(def.did) {
                         DefKind::Static | DefKind::Const | DefKind::AssocConst => {
-                            p!(print_value_path(did, substs))
+                            p!(print_value_path(def.did, substs))
                         }
                         _ => {
-                            if did.is_local() {
-                                let span = self.tcx().def_span(did);
+                            if def.did.is_local() {
+                                let span = self.tcx().def_span(def.did);
                                 if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span)
                                 {
                                     p!(write("{}", snip))
@@ -2049,9 +2049,9 @@ define_print_and_forward_display! {
                    print_value_path(closure_def_id, &[]),
                    write("` implements the trait `{}`", kind))
             }
-            &ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
+            &ty::PredicateKind::ConstEvaluatable(def, substs) => {
                 p!(write("the constant `"),
-                   print_value_path(def_id, substs),
+                   print_value_path(def.did, substs),
                    write("` can be evaluated"))
             }
             ty::PredicateKind::ConstEquate(c1, c2) => {
diff --git a/src/librustc_middle/ty/query/keys.rs b/src/librustc_middle/ty/query/keys.rs
index 4acf766f033d8..6b4bfadfb96cf 100644
--- a/src/librustc_middle/ty/query/keys.rs
+++ b/src/librustc_middle/ty/query/keys.rs
@@ -127,6 +127,27 @@ impl Key for (DefId, LocalDefId) {
     }
 }
 
+impl Key for ty::WithOptParam<DefId> {
+    type CacheSelector = DefaultCacheSelector;
+
+    fn query_crate(&self) -> CrateNum {
+        self.did.krate
+    }
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        self.did.default_span(tcx)
+    }
+}
+impl Key for ty::WithOptParam<LocalDefId> {
+    type CacheSelector = DefaultCacheSelector;
+
+    fn query_crate(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        self.did.default_span(tcx)
+    }
+}
+
 impl Key for (CrateNum, DefId) {
     type CacheSelector = DefaultCacheSelector;
 
@@ -307,3 +328,14 @@ impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) {
         DUMMY_SP
     }
 }
+
+impl<'tcx> Key for (ty::WithOptParam<DefId>, SubstsRef<'tcx>) {
+    type CacheSelector = DefaultCacheSelector;
+
+    fn query_crate(&self) -> CrateNum {
+        self.0.did.krate
+    }
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        tcx.def_span(self.0.did)
+    }
+}
diff --git a/src/librustc_middle/ty/query/mod.rs b/src/librustc_middle/ty/query/mod.rs
index 35d19b7603faf..f000ddadb20a5 100644
--- a/src/librustc_middle/ty/query/mod.rs
+++ b/src/librustc_middle/ty/query/mod.rs
@@ -216,4 +216,4 @@ mod sealed {
     }
 }
 
-use sealed::IntoQueryParam;
+pub(crate) use sealed::IntoQueryParam;
diff --git a/src/librustc_middle/ty/relate.rs b/src/librustc_middle/ty/relate.rs
index 14cddd11c438d..1a51080d2deac 100644
--- a/src/librustc_middle/ty/relate.rs
+++ b/src/librustc_middle/ty/relate.rs
@@ -599,12 +599,12 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
 
         // FIXME(const_generics): this is wrong, as it is a projection
         (
-            ty::ConstKind::Unevaluated(a_def_id, a_substs, a_promoted),
-            ty::ConstKind::Unevaluated(b_def_id, b_substs, b_promoted),
-        ) if a_def_id == b_def_id && a_promoted == b_promoted => {
+            ty::ConstKind::Unevaluated(a_def, a_substs, a_promoted),
+            ty::ConstKind::Unevaluated(b_def, b_substs, b_promoted),
+        ) if a_def == b_def && a_promoted == b_promoted => {
             let substs =
                 relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
-            Ok(ty::ConstKind::Unevaluated(a_def_id, &substs, a_promoted))
+            Ok(ty::ConstKind::Unevaluated(a_def, &substs, a_promoted))
         }
         _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
     };
diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs
index f736037b5c15a..4b4d9ef7a3457 100644
--- a/src/librustc_middle/ty/structural_impls.rs
+++ b/src/librustc_middle/ty/structural_impls.rs
@@ -243,8 +243,8 @@ impl fmt::Debug for ty::PredicateKind<'tcx> {
             ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
                 write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
             }
-            ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
-                write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
+            ty::PredicateKind::ConstEvaluatable(def, substs) => {
+                write!(f, "ConstEvaluatable({:?}, {:?})", def, substs)
             }
             ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
         }
@@ -261,23 +261,23 @@ CloneTypeFoldableAndLiftImpls! {
     (),
     bool,
     usize,
-    ::rustc_target::abi::VariantIdx,
+    rustc_target::abi::VariantIdx,
     u64,
     String,
     crate::middle::region::Scope,
-    ::rustc_ast::ast::FloatTy,
-    ::rustc_ast::ast::InlineAsmOptions,
-    ::rustc_ast::ast::InlineAsmTemplatePiece,
-    ::rustc_ast::ast::NodeId,
-    ::rustc_span::symbol::Symbol,
-    ::rustc_hir::def::Res,
-    ::rustc_hir::def_id::DefId,
-    ::rustc_hir::LlvmInlineAsmInner,
-    ::rustc_hir::MatchSource,
-    ::rustc_hir::Mutability,
-    ::rustc_hir::Unsafety,
-    ::rustc_target::asm::InlineAsmRegOrRegClass,
-    ::rustc_target::spec::abi::Abi,
+    rustc_ast::ast::FloatTy,
+    rustc_ast::ast::InlineAsmOptions,
+    rustc_ast::ast::InlineAsmTemplatePiece,
+    rustc_ast::ast::NodeId,
+    rustc_span::symbol::Symbol,
+    rustc_hir::def::Res,
+    rustc_hir::def_id::DefId,
+    rustc_hir::LlvmInlineAsmInner,
+    rustc_hir::MatchSource,
+    rustc_hir::Mutability,
+    rustc_hir::Unsafety,
+    rustc_target::asm::InlineAsmRegOrRegClass,
+    rustc_target::spec::abi::Abi,
     crate::mir::Local,
     crate::mir::Promoted,
     crate::traits::Reveal,
@@ -299,6 +299,8 @@ CloneTypeFoldableAndLiftImpls! {
     crate::ty::RegionVid,
     crate::ty::UniverseIndex,
     crate::ty::Variance,
+    crate::ty::WithOptParam<rustc_hir::def_id::LocalDefId>,
+    crate::ty::WithOptParam<rustc_hir::def_id::DefId>,
     ::rustc_span::Span,
 }
 
@@ -501,8 +503,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> {
             ty::PredicateKind::ObjectSafe(trait_def_id) => {
                 Some(ty::PredicateKind::ObjectSafe(trait_def_id))
             }
-            ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
-                tcx.lift(&substs).map(|substs| ty::PredicateKind::ConstEvaluatable(def_id, substs))
+            ty::PredicateKind::ConstEvaluatable(def, substs) => {
+                tcx.lift(&substs).map(|substs| ty::PredicateKind::ConstEvaluatable(def, substs))
             }
             ty::PredicateKind::ConstEquate(c1, c2) => {
                 tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2))
@@ -670,7 +672,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> {
     type Lifted = ty::InstanceDef<'tcx>;
     fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
         match *self {
-            ty::InstanceDef::Item(def_id) => Some(ty::InstanceDef::Item(def_id)),
+            ty::InstanceDef::Item(did) => Some(ty::InstanceDef::Item(did)),
             ty::InstanceDef::VtableShim(def_id) => Some(ty::InstanceDef::VtableShim(def_id)),
             ty::InstanceDef::ReifyShim(def_id) => Some(ty::InstanceDef::ReifyShim(def_id)),
             ty::InstanceDef::Intrinsic(def_id) => Some(ty::InstanceDef::Intrinsic(def_id)),
@@ -842,7 +844,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
         Self {
             substs: self.substs.fold_with(folder),
             def: match self.def {
-                Item(did) => Item(did.fold_with(folder)),
+                Item(def) => Item(def.fold_with(folder)),
                 VtableShim(did) => VtableShim(did.fold_with(folder)),
                 ReifyShim(did) => ReifyShim(did.fold_with(folder)),
                 Intrinsic(did) => Intrinsic(did.fold_with(folder)),
@@ -861,7 +863,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
         use crate::ty::InstanceDef::*;
         self.substs.visit_with(visitor)
             || match self.def {
-                Item(did) | VtableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => {
+                Item(def) => def.visit_with(visitor),
+                VtableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => {
                     did.visit_with(visitor)
                 }
                 FnPtrShim(did, ty) | CloneShim(did, ty) => {
@@ -1067,8 +1070,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
         match *self {
             ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)),
             ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)),
-            ty::ConstKind::Unevaluated(did, substs, promoted) => {
-                ty::ConstKind::Unevaluated(did, substs.fold_with(folder), promoted)
+            ty::ConstKind::Unevaluated(def, substs, promoted) => {
+                ty::ConstKind::Unevaluated(def, substs.fold_with(folder), promoted)
             }
             ty::ConstKind::Value(_)
             | ty::ConstKind::Bound(..)
diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs
index 1d680c3563675..fa67c9d051d32 100644
--- a/src/librustc_middle/ty/sty.rs
+++ b/src/librustc_middle/ty/sty.rs
@@ -2215,21 +2215,28 @@ impl<'tcx> Const<'tcx> {
     /// Literals and const generic parameters are eagerly converted to a constant, everything else
     /// becomes `Unevaluated`.
     pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
-        debug!("Const::from_anon_const(id={:?})", def_id);
+        Self::const_arg_from_anon_const(tcx, tcx.with_opt_param(def_id))
+    }
+
+    pub fn const_arg_from_anon_const(
+        tcx: TyCtxt<'tcx>,
+        def: ty::WithOptParam<LocalDefId>,
+    ) -> &'tcx Self {
+        debug!("Const::from_anon_const(def={:?})", def);
 
-        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
 
         let body_id = match tcx.hir().get(hir_id) {
             hir::Node::AnonConst(ac) => ac.body,
             _ => span_bug!(
-                tcx.def_span(def_id.to_def_id()),
+                tcx.def_span(def.did.to_def_id()),
                 "from_anon_const can only process anonymous constants"
             ),
         };
 
         let expr = &tcx.hir().body(body_id).value;
 
-        let ty = tcx.type_of(def_id.to_def_id());
+        let ty = tcx.type_of(def.ty_def_id());
 
         let lit_input = match expr.kind {
             hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
@@ -2276,8 +2283,8 @@ impl<'tcx> Const<'tcx> {
                 ty::ConstKind::Param(ty::ParamConst::new(index, name))
             }
             _ => ty::ConstKind::Unevaluated(
-                def_id.to_def_id(),
-                InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
+                def.to_global(),
+                InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
                 None,
             ),
         };
@@ -2345,7 +2352,7 @@ impl<'tcx> Const<'tcx> {
     /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
     /// unevaluated constant.
     pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> {
-        if let ConstKind::Unevaluated(did, substs, promoted) = self.val {
+        if let ConstKind::Unevaluated(def, substs, promoted) = self.val {
             use crate::mir::interpret::ErrorHandled;
 
             let param_env_and_substs = param_env.with_reveal_all().and(substs);
@@ -2361,7 +2368,7 @@ impl<'tcx> Const<'tcx> {
             // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
             // we can call `infcx.const_eval_resolve` which handles inference variables.
             let param_env_and_substs = if param_env_and_substs.needs_infer() {
-                tcx.param_env(did).and(InternalSubsts::identity_for_item(tcx, did))
+                tcx.param_env(def.did).and(InternalSubsts::identity_for_item(tcx, def.did))
             } else {
                 param_env_and_substs
             };
@@ -2371,7 +2378,7 @@ impl<'tcx> Const<'tcx> {
             let (param_env, substs) = param_env_and_substs.into_parts();
             // try to resolve e.g. associated constants to their definition on an impl, and then
             // evaluate the const.
-            match tcx.const_eval_resolve(param_env, did, substs, promoted, None) {
+            match tcx.const_eval_resolve(param_env, def, substs, promoted, None) {
                 // NOTE(eddyb) `val` contains no lifetimes/types/consts,
                 // and we use the original type, so nothing from `substs`
                 // (which may be identity substs, see above),
@@ -2431,7 +2438,7 @@ pub enum ConstKind<'tcx> {
 
     /// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
     /// variants when the code is monomorphic enough for that.
-    Unevaluated(DefId, SubstsRef<'tcx>, Option<Promoted>),
+    Unevaluated(ty::WithOptParam<DefId>, SubstsRef<'tcx>, Option<Promoted>),
 
     /// Used to hold computed value.
     Value(ConstValue<'tcx>),
diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
index 8d7944004c75e..94863272c6ff2 100644
--- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
@@ -190,7 +190,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     .ty;
             let needs_note = match ty.kind {
                 ty::Closure(id, _) => {
-                    let tables = self.infcx.tcx.typeck_tables_of(id.expect_local());
+                    let tables = self
+                        .infcx
+                        .tcx
+                        .typeck_tables_of(self.infcx.tcx.with_opt_param(id.expect_local()));
                     let hir_id = self.infcx.tcx.hir().as_local_hir_id(id.expect_local());
 
                     tables.closure_kind_origins().get(hir_id).is_none()
@@ -865,22 +868,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 format!("`{}` would have to be valid for `{}`...", name, region_name),
             );
 
-            let fn_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id);
+            let tcx = self.infcx.tcx;
+
+            let fn_hir_id = tcx.hir().as_local_hir_id(self.mir_def_id);
             err.span_label(
                 drop_span,
                 format!(
                     "...but `{}` will be dropped here, when the {} returns",
                     name,
-                    self.infcx
-                        .tcx
-                        .hir()
+                    tcx.hir()
                         .opt_name(fn_hir_id)
                         .map(|name| format!("function `{}`", name))
                         .unwrap_or_else(|| {
-                            match &self
-                                .infcx
-                                .tcx
-                                .typeck_tables_of(self.mir_def_id)
+                            match &tcx
+                                .typeck_tables_of(tcx.with_opt_param(self.mir_def_id))
                                 .node_type(fn_hir_id)
                                 .kind
                             {
diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs
index ca8e54ea28649..2eaf6fab4d02c 100644
--- a/src/librustc_mir/borrow_check/diagnostics/mod.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs
@@ -100,8 +100,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     let did = did.expect_local();
                     let hir_id = self.infcx.tcx.hir().as_local_hir_id(did);
 
-                    if let Some((span, name)) =
-                        self.infcx.tcx.typeck_tables_of(did).closure_kind_origins().get(hir_id)
+                    if let Some((span, name)) = self
+                        .infcx
+                        .tcx
+                        .typeck_tables_of(self.infcx.tcx.with_opt_param(did))
+                        .closure_kind_origins()
+                        .get(hir_id)
                     {
                         diag.span_note(
                             *span,
@@ -123,8 +127,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 let did = did.expect_local();
                 let hir_id = self.infcx.tcx.hir().as_local_hir_id(did);
 
-                if let Some((span, name)) =
-                    self.infcx.tcx.typeck_tables_of(did).closure_kind_origins().get(hir_id)
+                if let Some((span, name)) = self
+                    .infcx
+                    .tcx
+                    .typeck_tables_of(self.infcx.tcx.with_opt_param(did))
+                    .closure_kind_origins()
+                    .get(hir_id)
                 {
                     diag.span_note(
                         *span,
diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
index 4d4b6fb9386db..00cce45d30016 100644
--- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs
@@ -507,7 +507,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 .map(|(pos, _)| pos)
                 .next();
             let def_id = hir.local_def_id(item_id);
-            let tables = self.infcx.tcx.typeck_tables_of(def_id);
+            let tables = self.infcx.tcx.typeck_tables_of(self.infcx.tcx.with_opt_param(def_id));
             if let Some(ty::FnDef(def_id, _)) =
                 tables.node_type_opt(func.hir_id).as_ref().map(|ty| &ty.kind)
             {
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 03b663eb75056..27bf01a1882b1 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -90,14 +90,14 @@ pub fn provide(providers: &mut Providers<'_>) {
     *providers = Providers { mir_borrowck, ..*providers };
 }
 
-fn mir_borrowck(tcx: TyCtxt<'_>, def_id: LocalDefId) -> BorrowCheckResult<'_> {
-    let (input_body, promoted) = tcx.mir_validated(def_id);
-    debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id.to_def_id()));
+fn mir_borrowck(tcx: TyCtxt<'_>, def: ty::WithOptParam<LocalDefId>) -> BorrowCheckResult<'_> {
+    let (input_body, promoted) = tcx.mir_validated(def);
+    debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
 
     let opt_closure_req = tcx.infer_ctxt().enter(|infcx| {
         let input_body: &Body<'_> = &input_body.borrow();
         let promoted: &IndexVec<_, _> = &promoted.borrow();
-        do_mir_borrowck(&infcx, input_body, promoted, def_id)
+        do_mir_borrowck(&infcx, input_body, promoted, def)
     });
     debug!("mir_borrowck done");
 
@@ -108,13 +108,13 @@ fn do_mir_borrowck<'a, 'tcx>(
     infcx: &InferCtxt<'a, 'tcx>,
     input_body: &Body<'tcx>,
     input_promoted: &IndexVec<Promoted, Body<'tcx>>,
-    def_id: LocalDefId,
+    def: ty::WithOptParam<LocalDefId>,
 ) -> BorrowCheckResult<'tcx> {
-    debug!("do_mir_borrowck(def_id = {:?})", def_id);
+    debug!("do_mir_borrowck(def_id = {:?})", def);
 
     let tcx = infcx.tcx;
-    let param_env = tcx.param_env(def_id);
-    let id = tcx.hir().as_local_hir_id(def_id);
+    let param_env = tcx.param_env(def.did);
+    let id = tcx.hir().as_local_hir_id(def.did);
 
     let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
     for var_debug_info in &input_body.var_debug_info {
@@ -135,13 +135,13 @@ fn do_mir_borrowck<'a, 'tcx>(
     }
 
     // Gather the upvars of a closure, if any.
-    let tables = tcx.typeck_tables_of(def_id);
+    let tables = tcx.typeck_tables_of(def);
     if let Some(ErrorReported) = tables.tainted_by_errors {
         infcx.set_tainted_by_errors();
     }
     let upvars: Vec<_> = tables
         .closure_captures
-        .get(&def_id.to_def_id())
+        .get(&def.did.to_def_id())
         .into_iter()
         .flat_map(|v| v.values())
         .map(|upvar_id| {
@@ -171,8 +171,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     // will have a lifetime tied to the inference context.
     let mut body = input_body.clone();
     let mut promoted = input_promoted.clone();
-    let free_regions =
-        nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body, &mut promoted);
+    let free_regions = nll::replace_regions_in_mir(infcx, def, param_env, &mut body, &mut promoted);
     let body = &body; // no further changes
 
     let location_table = &LocationTable::new(&body);
@@ -190,7 +189,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     let mdpe = MoveDataParamEnv { move_data, param_env };
 
     let mut flow_inits = MaybeInitializedPlaces::new(tcx, &body, &mdpe)
-        .into_engine(tcx, &body, def_id.to_def_id())
+        .into_engine(tcx, &body, def.did.to_def_id())
         .iterate_to_fixpoint()
         .into_results_cursor(&body);
 
@@ -207,7 +206,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         nll_errors,
     } = nll::compute_regions(
         infcx,
-        def_id,
+        def.did,
         free_regions,
         body,
         &promoted,
@@ -223,7 +222,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     // write unit-tests, as well as helping with debugging.
     nll::dump_mir_results(
         infcx,
-        MirSource::item(def_id.to_def_id()),
+        MirSource::item(def.did.to_def_id()),
         &body,
         &regioncx,
         &opt_closure_req,
@@ -234,7 +233,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     nll::dump_annotation(
         infcx,
         &body,
-        def_id.to_def_id(),
+        def.did.to_def_id(),
         &regioncx,
         &opt_closure_req,
         &opaque_type_values,
@@ -249,13 +248,13 @@ fn do_mir_borrowck<'a, 'tcx>(
     let regioncx = Rc::new(regioncx);
 
     let flow_borrows = Borrows::new(tcx, &body, regioncx.clone(), &borrow_set)
-        .into_engine(tcx, &body, def_id.to_def_id())
+        .into_engine(tcx, &body, def.did.to_def_id())
         .iterate_to_fixpoint();
     let flow_uninits = MaybeUninitializedPlaces::new(tcx, &body, &mdpe)
-        .into_engine(tcx, &body, def_id.to_def_id())
+        .into_engine(tcx, &body, def.did.to_def_id())
         .iterate_to_fixpoint();
     let flow_ever_inits = EverInitializedPlaces::new(tcx, &body, &mdpe)
-        .into_engine(tcx, &body, def_id.to_def_id())
+        .into_engine(tcx, &body, def.did.to_def_id())
         .iterate_to_fixpoint();
 
     let movable_generator = match tcx.hir().get(id) {
@@ -274,7 +273,7 @@ fn do_mir_borrowck<'a, 'tcx>(
             let mut promoted_mbcx = MirBorrowckCtxt {
                 infcx,
                 body: promoted_body,
-                mir_def_id: def_id,
+                mir_def_id: def.did,
                 move_data: &move_data,
                 location_table: &LocationTable::new(promoted_body),
                 movable_generator,
@@ -306,7 +305,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     let mut mbcx = MirBorrowckCtxt {
         infcx,
         body,
-        mir_def_id: def_id,
+        mir_def_id: def.did,
         move_data: &mdpe.move_data,
         location_table,
         movable_generator,
@@ -1348,8 +1347,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 // in order to populate our used_mut set.
                 match **aggregate_kind {
                     AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) => {
+                        let tcx = self.infcx.tcx;
                         let BorrowCheckResult { used_mut_upvars, .. } =
-                            self.infcx.tcx.mir_borrowck(def_id.expect_local());
+                            tcx.mir_borrowck(tcx.with_opt_param(def_id.expect_local()));
                         debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
                         for field in used_mut_upvars {
                             self.propagate_closure_used_mut_upvar(&operands[field.index()]);
diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs
index ea68364be37a3..67eca353f8590 100644
--- a/src/librustc_mir/borrow_check/nll.rs
+++ b/src/librustc_mir/borrow_check/nll.rs
@@ -59,20 +59,20 @@ crate struct NllOutput<'tcx> {
 /// `compute_regions`.
 pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
-    def_id: LocalDefId,
+    def: ty::WithOptParam<LocalDefId>,
     param_env: ty::ParamEnv<'tcx>,
     body: &mut Body<'tcx>,
     promoted: &mut IndexVec<Promoted, Body<'tcx>>,
 ) -> UniversalRegions<'tcx> {
-    debug!("replace_regions_in_mir(def_id={:?})", def_id);
+    debug!("replace_regions_in_mir(def={:?})", def);
 
     // Compute named region information. This also renumbers the inputs/outputs.
-    let universal_regions = UniversalRegions::new(infcx, def_id, param_env);
+    let universal_regions = UniversalRegions::new(infcx, def, param_env);
 
     // Replace all remaining regions with fresh inference variables.
     renumber::renumber_mir(infcx, body, promoted);
 
-    let source = MirSource::item(def_id.to_def_id());
+    let source = MirSource::item(def.did.to_def_id());
     mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, body, |_, _| Ok(()));
 
     universal_regions
diff --git a/src/librustc_mir/borrow_check/type_check/input_output.rs b/src/librustc_mir/borrow_check/type_check/input_output.rs
index edd2dc3c2de55..55031baa91ab7 100644
--- a/src/librustc_mir/borrow_check/type_check/input_output.rs
+++ b/src/librustc_mir/borrow_check/type_check/input_output.rs
@@ -36,7 +36,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         if !self.tcx().is_closure(self.mir_def_id.to_def_id()) {
             user_provided_sig = None;
         } else {
-            let typeck_tables = self.tcx().typeck_tables_of(self.mir_def_id);
+            let typeck_tables =
+                self.tcx().typeck_tables_of(self.tcx().with_opt_param(self.mir_def_id));
             user_provided_sig =
                 match typeck_tables.user_provided_sigs.get(&self.mir_def_id.to_def_id()) {
                     None => None,
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index 0e35cafb9f3e9..45d2981d3ec70 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -321,7 +321,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
             }
         } else {
             let tcx = self.tcx();
-            if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.literal.val {
+            if let ty::ConstKind::Unevaluated(def, substs, promoted) = constant.literal.val {
                 if let Some(promoted) = promoted {
                     let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
                                      promoted: &Body<'tcx>,
@@ -357,7 +357,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
                         ConstraintCategory::Boring,
                         self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
                             constant.literal.ty,
-                            def_id,
+                            def.did,
                             UserSubsts { substs, user_self_ty: None },
                         )),
                     ) {
@@ -1238,8 +1238,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         let tcx = infcx.tcx;
         let param_env = self.param_env;
         let body = self.body;
-        let concrete_opaque_types =
-            &tcx.typeck_tables_of(anon_owner_def_id.expect_local()).concrete_opaque_types;
+        let concrete_opaque_types = &tcx
+            .typeck_tables_of(tcx.with_opt_param(anon_owner_def_id.expect_local()))
+            .concrete_opaque_types;
         let mut opaque_type_values = Vec::new();
 
         debug!("eq_opaque_type_and_type: mir_def_id={:?}", self.mir_def_id);
@@ -2637,7 +2638,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         substs: SubstsRef<'tcx>,
         location: Location,
     ) -> ty::InstantiatedPredicates<'tcx> {
-        if let Some(ref closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements
+        if let Some(ref closure_region_requirements) =
+            tcx.mir_borrowck(tcx.with_opt_param(def_id)).closure_requirements
         {
             let closure_constraints = QueryRegionConstraints {
                 outlives: closure_region_requirements.apply_requirements(
diff --git a/src/librustc_mir/borrow_check/universal_regions.rs b/src/librustc_mir/borrow_check/universal_regions.rs
index 3003f4639d9fa..fbb21a312985f 100644
--- a/src/librustc_mir/borrow_check/universal_regions.rs
+++ b/src/librustc_mir/borrow_check/universal_regions.rs
@@ -227,12 +227,12 @@ impl<'tcx> UniversalRegions<'tcx> {
     /// known between those regions.
     pub fn new(
         infcx: &InferCtxt<'_, 'tcx>,
-        mir_def_id: LocalDefId,
+        mir_def: ty::WithOptParam<LocalDefId>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> Self {
         let tcx = infcx.tcx;
-        let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id);
-        UniversalRegionsBuilder { infcx, mir_def_id: mir_def_id.to_def_id(), mir_hir_id, param_env }
+        let mir_hir_id = tcx.hir().as_local_hir_id(mir_def.did);
+        UniversalRegionsBuilder { infcx, mir_def: mir_def.to_global(), mir_hir_id, param_env }
             .build()
     }
 
@@ -389,7 +389,7 @@ impl<'tcx> UniversalRegions<'tcx> {
 
 struct UniversalRegionsBuilder<'cx, 'tcx> {
     infcx: &'cx InferCtxt<'cx, 'tcx>,
-    mir_def_id: DefId,
+    mir_def: ty::WithOptParam<DefId>,
     mir_hir_id: HirId,
     param_env: ty::ParamEnv<'tcx>,
 }
@@ -398,7 +398,7 @@ const FR: NLLRegionVariableOrigin = NLLRegionVariableOrigin::FreeRegion;
 
 impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
     fn build(self) -> UniversalRegions<'tcx> {
-        debug!("build(mir_def_id={:?})", self.mir_def_id);
+        debug!("build(mir_def={:?})", self.mir_def);
 
         let param_env = self.param_env;
         debug!("build: param_env={:?}", param_env);
@@ -418,7 +418,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         let mut indices = self.compute_indices(fr_static, defining_ty);
         debug!("build: indices={:?}", indices);
 
-        let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def_id);
+        let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did);
 
         // If this is a closure or generator, then the late-bound regions from the enclosing
         // function are actually external regions to us. For example, here, 'a is not local
@@ -426,8 +426,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         // fn foo<'a>() {
         //     let c = || { let x: &'a u32 = ...; }
         // }
-        if self.mir_def_id != closure_base_def_id {
-            self.infcx.replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices)
+        if self.mir_def.did != closure_base_def_id {
+            self.infcx
+                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices)
         }
 
         let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);
@@ -437,15 +438,15 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         let first_local_index = self.infcx.num_region_vars();
         let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars(
             FR,
-            self.mir_def_id,
+            self.mir_def.did,
             &bound_inputs_and_output,
             &mut indices,
         );
         // Converse of above, if this is a function then the late-bound regions declared on its
         // signature are local to the fn.
-        if self.mir_def_id == closure_base_def_id {
+        if self.mir_def.did == closure_base_def_id {
             self.infcx
-                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def_id, &mut indices);
+                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
         }
 
         let (unnormalized_output_ty, mut unnormalized_input_tys) =
@@ -457,7 +458,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             if self.infcx.tcx.fn_sig(def_id).c_variadic() {
                 let va_list_did = self.infcx.tcx.require_lang_item(
                     lang_items::VaListTypeLangItem,
-                    Some(self.infcx.tcx.def_span(self.mir_def_id)),
+                    Some(self.infcx.tcx.def_span(self.mir_def.did)),
                 );
                 let region = self
                     .infcx
@@ -508,14 +509,14 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
     /// see `DefiningTy` for details.
     fn defining_ty(&self) -> DefiningTy<'tcx> {
         let tcx = self.infcx.tcx;
-        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
+        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did);
 
         match tcx.hir().body_owner_kind(self.mir_hir_id) {
             BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
-                let defining_ty = if self.mir_def_id == closure_base_def_id {
+                let defining_ty = if self.mir_def.did == closure_base_def_id {
                     tcx.type_of(closure_base_def_id)
                 } else {
-                    let tables = tcx.typeck_tables_of(self.mir_def_id.expect_local());
+                    let tables = tcx.typeck_tables_of(self.mir_def.expect_local());
                     tables.node_type(self.mir_hir_id)
                 };
 
@@ -531,20 +532,20 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                     }
                     ty::FnDef(def_id, substs) => DefiningTy::FnDef(def_id, substs),
                     _ => span_bug!(
-                        tcx.def_span(self.mir_def_id),
+                        tcx.def_span(self.mir_def.did),
                         "expected defining type for `{:?}`: `{:?}`",
-                        self.mir_def_id,
+                        self.mir_def.did,
                         defining_ty
                     ),
                 }
             }
 
             BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
-                assert_eq!(closure_base_def_id, self.mir_def_id);
+                assert_eq!(closure_base_def_id, self.mir_def.did);
                 let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
                 let substs =
                     self.infcx.replace_free_regions_with_nll_infer_vars(FR, &identity_substs);
-                DefiningTy::Const(self.mir_def_id, substs)
+                DefiningTy::Const(self.mir_def.did, substs)
             }
         }
     }
@@ -559,7 +560,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         defining_ty: DefiningTy<'tcx>,
     ) -> UniversalRegionIndices<'tcx> {
         let tcx = self.infcx.tcx;
-        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
+        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did);
         let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
         let fr_substs = match defining_ty {
             DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
@@ -593,7 +594,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         let tcx = self.infcx.tcx;
         match defining_ty {
             DefiningTy::Closure(def_id, substs) => {
-                assert_eq!(self.mir_def_id, def_id);
+                assert_eq!(self.mir_def.did, def_id);
                 let closure_sig = substs.as_closure().sig();
                 let inputs_and_output = closure_sig.inputs_and_output();
                 let closure_ty = tcx.closure_env_ty(def_id, substs).unwrap();
@@ -617,7 +618,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             }
 
             DefiningTy::Generator(def_id, substs, movability) => {
-                assert_eq!(self.mir_def_id, def_id);
+                assert_eq!(self.mir_def.did, def_id);
                 let resume_ty = substs.as_generator().resume_ty();
                 let output = substs.as_generator().return_ty();
                 let generator_ty = tcx.mk_generator(def_id, substs, movability);
@@ -635,8 +636,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             DefiningTy::Const(def_id, _) => {
                 // For a constant body, there are no inputs, and one
                 // "output" (the type of the constant).
-                assert_eq!(self.mir_def_id, def_id);
-                let ty = tcx.type_of(def_id);
+                assert_eq!(self.mir_def.did, def_id);
+                let ty = tcx.type_of(self.mir_def.ty_def_id());
                 let ty = indices.fold_to_region_vids(tcx, &ty);
                 ty::Binder::dummy(tcx.intern_type_list(&[ty]))
             }
diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs
index d62300b3f5541..a014a2255b7a2 100644
--- a/src/librustc_mir/const_eval/eval_queries.rs
+++ b/src/librustc_mir/const_eval/eval_queries.rs
@@ -288,17 +288,17 @@ pub fn const_eval_raw_provider<'tcx>(
     }
 
     let cid = key.value;
-    let def_id = cid.instance.def.def_id();
+    let def = cid.instance.def.with_opt_param();
 
-    if let Some(def_id) = def_id.as_local() {
-        if tcx.has_typeck_tables(def_id) {
-            if let Some(error_reported) = tcx.typeck_tables_of(def_id).tainted_by_errors {
+    if let Some(def) = def.as_local() {
+        if tcx.has_typeck_tables(def.did) {
+            if let Some(error_reported) = tcx.typeck_tables_of(def).tainted_by_errors {
                 return Err(ErrorHandled::Reported(error_reported));
             }
         }
     }
 
-    let is_static = tcx.is_static(def_id);
+    let is_static = tcx.is_static(def.did);
 
     let mut ecx = InterpCx::new(
         tcx,
@@ -334,9 +334,9 @@ pub fn const_eval_raw_provider<'tcx>(
                 }
 
                 v
-            } else if def_id.is_local() {
+            } else if def.did.is_local() {
                 // constant defined in this crate, we can figure out a lint level!
-                match tcx.def_kind(def_id) {
+                match tcx.def_kind(def.did) {
                     // constants never produce a hard error at the definition site. Anything else is
                     // a backwards compatibility hazard (and will break old versions of winapi for
                     // sure)
@@ -346,9 +346,9 @@ pub fn const_eval_raw_provider<'tcx>(
                     // validation thus preventing such a hard error from being a backwards
                     // compatibility hazard
                     DefKind::Const | DefKind::AssocConst => {
-                        let hir_id = tcx.hir().as_local_hir_id(def_id.expect_local());
+                        let hir_id = tcx.hir().as_local_hir_id(def.did.expect_local());
                         err.report_as_lint(
-                            tcx.at(tcx.def_span(def_id)),
+                            tcx.at(tcx.def_span(def.did)),
                             "any use of this value will cause an error",
                             hir_id,
                             Some(err.span),
@@ -359,7 +359,7 @@ pub fn const_eval_raw_provider<'tcx>(
                     // deny-by-default lint
                     _ => {
                         if let Some(p) = cid.promoted {
-                            let span = tcx.promoted_mir(def_id)[p].span;
+                            let span = tcx.promoted_mir(def)[p].span;
                             if let err_inval!(ReferencedConstant) = err.error {
                                 err.report_as_error(
                                     tcx.at(span),
@@ -369,7 +369,7 @@ pub fn const_eval_raw_provider<'tcx>(
                                 err.report_as_lint(
                                     tcx.at(span),
                                     "reaching this expression at runtime will panic or abort",
-                                    tcx.hir().as_local_hir_id(def_id.expect_local()),
+                                    tcx.hir().as_local_hir_id(def.did.expect_local()),
                                     Some(err.span),
                                 )
                             }
diff --git a/src/librustc_mir/const_eval/machine.rs b/src/librustc_mir/const_eval/machine.rs
index dc13126df0e4c..2693a82eadf19 100644
--- a/src/librustc_mir/const_eval/machine.rs
+++ b/src/librustc_mir/const_eval/machine.rs
@@ -191,11 +191,11 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
         debug!("find_mir_or_eval_fn: {:?}", instance);
 
         // Only check non-glue functions
-        if let ty::InstanceDef::Item(def_id) = instance.def {
+        if let ty::InstanceDef::Item(def) = instance.def {
             // Execution might have wandered off into other crates, so we cannot do a stability-
             // sensitive check here.  But we can at least rule out functions that are not const
             // at all.
-            if ecx.tcx.is_const_fn_raw(def_id) {
+            if ecx.tcx.is_const_fn_raw(def.did) {
                 // If this function is a `const fn` then under certain circumstances we
                 // can evaluate call via the query system, thus memoizing all future calls.
                 if ecx.try_eval_const_fn_call(instance, ret, args)? {
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 95e193b625354..dbc1d202003c5 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -400,24 +400,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         promoted: Option<mir::Promoted>,
     ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
         // do not continue if typeck errors occurred (can only occur in local crate)
-        let did = instance.def_id();
-        if let Some(did) = did.as_local() {
-            if self.tcx.has_typeck_tables(did) {
-                if let Some(error_reported) = self.tcx.typeck_tables_of(did).tainted_by_errors {
+        let def = instance.with_opt_param();
+        if let Some(def) = def.as_local() {
+            if self.tcx.has_typeck_tables(def.did) {
+                if let Some(error_reported) = self.tcx.typeck_tables_of(def).tainted_by_errors {
                     throw_inval!(TypeckError(error_reported))
                 }
             }
         }
         trace!("load mir(instance={:?}, promoted={:?})", instance, promoted);
         if let Some(promoted) = promoted {
-            return Ok(&self.tcx.promoted_mir(did)[promoted]);
+            return Ok(&self.tcx.promoted_mir(def)[promoted]);
         }
         match instance {
-            ty::InstanceDef::Item(def_id) => {
-                if self.tcx.is_mir_available(did) {
-                    Ok(self.tcx.optimized_mir(did))
+            ty::InstanceDef::Item(_) => {
+                if self.tcx.is_mir_available(def.did) {
+                    Ok(self.tcx.optimized_mir(def))
                 } else {
-                    throw_unsup!(NoMirFor(def_id))
+                    throw_unsup!(NoMirFor(def.did))
                 }
             }
             _ => Ok(self.tcx.instance_mir(instance)),
@@ -448,15 +448,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     }
 
     /// The `substs` are assumed to already be in our interpreter "universe" (param_env).
+    #[inline]
     pub(super) fn resolve(
         &self,
         def_id: DefId,
         substs: SubstsRef<'tcx>,
     ) -> InterpResult<'tcx, ty::Instance<'tcx>> {
-        trace!("resolve: {:?}, {:#?}", def_id, substs);
+        self.resolve_const_arg(ty::WithOptParam::dummy(def_id), substs)
+    }
+
+    pub(super) fn resolve_const_arg(
+        &self,
+        def: ty::WithOptParam<DefId>,
+        substs: SubstsRef<'tcx>,
+    ) -> InterpResult<'tcx, ty::Instance<'tcx>> {
+        trace!("resolve: {:?}, {:#?}", def, substs);
         trace!("param_env: {:#?}", self.param_env);
         trace!("substs: {:#?}", substs);
-        match ty::Instance::resolve(*self.tcx, self.param_env, def_id, substs) {
+        match ty::Instance::resolve_const_arg(*self.tcx, self.param_env, def, substs) {
             Ok(Some(instance)) => Ok(instance),
             Ok(None) => throw_inval!(TooGeneric),
 
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 38948ee53846a..17b9c31d6b172 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -531,8 +531,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let val_val = match val.val {
             ty::ConstKind::Param(_) => throw_inval!(TooGeneric),
             ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)),
-            ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
-                let instance = self.resolve(def_id, substs)?;
+            ty::ConstKind::Unevaluated(def, substs, promoted) => {
+                let instance = self.resolve_const_arg(def, substs)?;
                 // We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation.
                 // The reason we use `const_eval_raw` everywhere else is to prevent cycles during
                 // validation, because validation automatically reads through any references, thus
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index 3bb9ba3712058..44f0b86d564d5 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -226,7 +226,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
             ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
                 let mut name = None;
                 if let Some(def_id) = def_id.as_local() {
-                    let tables = self.ecx.tcx.typeck_tables_of(def_id);
+                    let tables = self.ecx.tcx.typeck_tables_of(self.ecx.tcx.with_opt_param(def_id));
                     if let Some(upvars) = tables.closure_captures.get(&def_id.to_def_id()) {
                         // Sometimes the index is beyond the number of upvars (seen
                         // for a generator).
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index f9b3c319c1f66..6a3e63eebf1e6 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -622,12 +622,12 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
 
         match substituted_constant.val {
             ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output),
-            ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
-                match self.tcx.const_eval_resolve(param_env, def_id, substs, promoted, None) {
+            ty::ConstKind::Unevaluated(def, substs, promoted) => {
+                match self.tcx.const_eval_resolve(param_env, def, substs, promoted, None) {
                     Ok(val) => collect_const_value(self.tcx, val, self.output),
                     Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => {}
                     Err(ErrorHandled::TooGeneric) => span_bug!(
-                        self.tcx.def_span(def_id),
+                        self.tcx.def_span(def.did),
                         "collection encountered polymorphic constant",
                     ),
                 }
@@ -768,7 +768,8 @@ fn visit_instance_use<'tcx>(
 // need a mono item.
 fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
     let def_id = match instance.def {
-        ty::InstanceDef::Item(def_id) | ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id,
+        ty::InstanceDef::Item(def) => def.did,
+        ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id,
 
         ty::InstanceDef::VtableShim(..)
         | ty::InstanceDef::ReifyShim(..)
diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs
index a945c1d626a9a..d9f127eb3f677 100644
--- a/src/librustc_mir/monomorphize/partitioning.rs
+++ b/src/librustc_mir/monomorphize/partitioning.rs
@@ -314,7 +314,8 @@ fn mono_item_visibility(
     };
 
     let def_id = match instance.def {
-        InstanceDef::Item(def_id) | InstanceDef::DropGlue(def_id, Some(_)) => def_id,
+        InstanceDef::Item(def) => def.did,
+        InstanceDef::DropGlue(def_id, Some(_)) => def_id,
 
         // These are all compiler glue and such, never exported, always hidden.
         InstanceDef::VtableShim(..)
@@ -704,7 +705,7 @@ fn characteristic_def_id_of_mono_item<'tcx>(
     match mono_item {
         MonoItem::Fn(instance) => {
             let def_id = match instance.def {
-                ty::InstanceDef::Item(def_id) => def_id,
+                ty::InstanceDef::Item(def) => def.did,
                 ty::InstanceDef::VtableShim(..)
                 | ty::InstanceDef::ReifyShim(..)
                 | ty::InstanceDef::FnPtrShim(..)
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 8327affd982ed..27b57ffef8b34 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -169,7 +169,8 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
 
     // Check if this is a generator, if so, return the drop glue for it
     if let Some(&ty::TyS { kind: ty::Generator(gen_def_id, substs, _), .. }) = ty {
-        let body = &**tcx.optimized_mir(gen_def_id).generator_drop.as_ref().unwrap();
+        let body =
+            &**tcx.optimized_mir(tcx.with_opt_param(gen_def_id)).generator_drop.as_ref().unwrap();
         return body.subst(tcx, substs);
     }
 
diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs
index e2893e81a2ce6..582a2c85243fd 100644
--- a/src/librustc_mir/transform/check_consts/qualifs.rs
+++ b/src/librustc_mir/transform/check_consts/qualifs.rs
@@ -244,11 +244,11 @@ where
     };
 
     // Check the qualifs of the value of `const` items.
-    if let ty::ConstKind::Unevaluated(def_id, _, promoted) = constant.literal.val {
+    if let ty::ConstKind::Unevaluated(def, _, promoted) = constant.literal.val {
         assert!(promoted.is_none());
         // Don't peek inside trait associated constants.
-        if cx.tcx.trait_of_item(def_id).is_none() {
-            let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def_id);
+        if cx.tcx.trait_of_item(def.did).is_none() {
+            let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def);
             if !Q::in_qualifs(&qualifs) {
                 return false;
             }
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index d263bf12e8868..a7c21debba410 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -537,8 +537,8 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                     let instance = Instance::resolve(self.tcx, self.param_env, def_id, substs);
                     debug!("Resolving ({:?}) -> {:?}", def_id, instance);
                     if let Ok(Some(func)) = instance {
-                        if let InstanceDef::Item(def_id) = func.def {
-                            if is_const_fn(self.tcx, def_id) {
+                        if let InstanceDef::Item(def) = func.def {
+                            if is_const_fn(self.tcx, def.did) {
                                 return;
                             }
                         }
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index b8f725e967ddb..d15524247e67c 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -146,8 +146,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
                     }
                 }
                 &AggregateKind::Closure(def_id, _) | &AggregateKind::Generator(def_id, _, _) => {
-                    let UnsafetyCheckResult { violations, unsafe_blocks } =
-                        self.tcx.unsafety_check_result(def_id.expect_local());
+                    let UnsafetyCheckResult { violations, unsafe_blocks } = self
+                        .tcx
+                        .unsafety_check_result(self.tcx.with_opt_param(def_id.expect_local()));
                     self.register_violations(&violations, &unsafe_blocks);
                 }
             },
@@ -535,28 +536,31 @@ fn check_unused_unsafe(
     intravisit::Visitor::visit_body(&mut visitor, body);
 }
 
-fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: LocalDefId) -> UnsafetyCheckResult {
-    debug!("unsafety_violations({:?})", def_id);
+fn unsafety_check_result(
+    tcx: TyCtxt<'_>,
+    def: ty::WithOptParam<LocalDefId>,
+) -> UnsafetyCheckResult {
+    debug!("unsafety_violations({:?})", def);
 
     // N.B., this borrow is valid because all the consumers of
     // `mir_built` force this.
-    let body = &tcx.mir_built(def_id).borrow();
+    let body = &tcx.mir_built(def).borrow();
 
-    let param_env = tcx.param_env(def_id);
+    let param_env = tcx.param_env(def.did);
 
-    let id = tcx.hir().as_local_hir_id(def_id);
+    let id = tcx.hir().as_local_hir_id(def.did);
     let (const_context, min_const_fn) = match tcx.hir().body_owner_kind(id) {
         hir::BodyOwnerKind::Closure => (false, false),
         hir::BodyOwnerKind::Fn => {
-            (tcx.is_const_fn_raw(def_id.to_def_id()), is_min_const_fn(tcx, def_id.to_def_id()))
+            (tcx.is_const_fn_raw(def.did.to_def_id()), is_min_const_fn(tcx, def.did.to_def_id()))
         }
         hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false),
     };
     let mut checker =
-        UnsafetyChecker::new(const_context, min_const_fn, body, def_id, tcx, param_env);
+        UnsafetyChecker::new(const_context, min_const_fn, body, def.did, tcx, param_env);
     checker.visit_body(&body);
 
-    check_unused_unsafe(tcx, def_id, &checker.used_unsafe, &mut checker.inherited_blocks);
+    check_unused_unsafe(tcx, def.did, &checker.used_unsafe, &mut checker.inherited_blocks);
     UnsafetyCheckResult {
         violations: checker.violations.into(),
         unsafe_blocks: checker.inherited_blocks.into(),
@@ -651,7 +655,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         return;
     }
 
-    let UnsafetyCheckResult { violations, unsafe_blocks } = tcx.unsafety_check_result(def_id);
+    let UnsafetyCheckResult { violations, unsafe_blocks } =
+        tcx.unsafety_check_result(tcx.with_opt_param(def_id));
 
     for &UnsafetyViolation { source_info, lint_root, description, details, kind } in
         violations.iter()
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 068d055fa78f8..2a0dbfc9e562a 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -102,14 +102,14 @@ impl Inliner<'tcx> {
                     // not inline us. This trick only works without incremental compilation.
                     // So don't do it if that is enabled.
                     if !self.tcx.dep_graph.is_fully_enabled() && self_hir_id < callee_hir_id {
-                        self.tcx.optimized_mir(callsite.callee)
+                        self.tcx.optimized_mir(self.tcx.with_opt_param(callsite.callee))
                     } else {
                         continue;
                     }
                 } else {
                     // This cannot result in a cycle since the callee MIR is from another crate
                     // and is already optimized.
-                    self.tcx.optimized_mir(callsite.callee)
+                    self.tcx.optimized_mir(self.tcx.with_opt_param(callsite.callee))
                 };
 
                 let callee_body = if self.consider_optimizing(callsite, callee_body) {
diff --git a/src/librustc_mir/transform/instrument_coverage.rs b/src/librustc_mir/transform/instrument_coverage.rs
index 06b648ab5a908..8ba19fef2813d 100644
--- a/src/librustc_mir/transform/instrument_coverage.rs
+++ b/src/librustc_mir/transform/instrument_coverage.rs
@@ -25,7 +25,7 @@ pub struct InstrumentCoverage;
 /// constructing the arguments for `llvm.instrprof.increment`.
 pub(crate) fn provide(providers: &mut Providers<'_>) {
     providers.coverage_data = |tcx, def_id| {
-        let mir_body = tcx.optimized_mir(def_id);
+        let mir_body = tcx.optimized_mir(ty::WithOptParam::dummy(def_id));
         // FIXME(richkadel): The current implementation assumes the MIR for the given DefId
         // represents a single function. Validate and/or correct if inlining and/or monomorphization
         // invalidates these assumptions.
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 8ca240d2c7da7..9236bd3a2d454 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -9,7 +9,7 @@ use rustc_middle::mir::visit::Visitor as _;
 use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::steal::Steal;
-use rustc_middle::ty::{InstanceDef, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, InstanceDef, TyCtxt, TypeFoldable};
 use rustc_span::{Span, Symbol};
 use std::borrow::Cow;
 
@@ -116,13 +116,18 @@ pub struct MirSource<'tcx> {
 
 impl<'tcx> MirSource<'tcx> {
     pub fn item(def_id: DefId) -> Self {
-        MirSource { instance: InstanceDef::Item(def_id), promoted: None }
+        MirSource { instance: InstanceDef::Item(ty::WithOptParam::dummy(def_id)), promoted: None }
     }
 
     #[inline]
-    pub fn def_id(&self) -> DefId {
+    pub fn def_id(self) -> DefId {
         self.instance.def_id()
     }
+
+    #[inline]
+    pub fn with_opt_param(self) -> ty::WithOptParam<DefId> {
+        self.instance.with_opt_param()
+    }
 }
 
 /// Generates a default name for the pass based on the name of the
@@ -202,8 +207,8 @@ pub fn run_passes(
     }
 }
 
-fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs {
-    let const_kind = tcx.hir().body_const_context(def_id.expect_local());
+fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptParam<DefId>) -> ConstQualifs {
+    let const_kind = tcx.hir().body_const_context(def.did.expect_local());
 
     // No need to const-check a non-const `fn`.
     if const_kind.is_none() {
@@ -214,15 +219,20 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs {
     // cannot yet be stolen), because `mir_validated()`, which steals
     // from `mir_const(), forces this query to execute before
     // performing the steal.
-    let body = &tcx.mir_const(def_id).borrow();
+    let body = &tcx.mir_const(def).borrow();
 
     if body.return_ty().references_error() {
         tcx.sess.delay_span_bug(body.span, "mir_const_qualif: MIR had errors");
         return Default::default();
     }
 
-    let ccx =
-        check_consts::ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) };
+    let ccx = check_consts::ConstCx {
+        body,
+        tcx,
+        def_id: def.did,
+        const_kind,
+        param_env: tcx.param_env(def.did),
+    };
 
     let mut validator = check_consts::validation::Validator::new(&ccx);
     validator.check_body();
@@ -233,22 +243,28 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs {
 }
 
 /// Make MIR ready for const evaluation. This is run on all MIR, not just on consts!
-fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> Steal<Body<'_>> {
-    let def_id = def_id.expect_local();
+fn mir_const(tcx: TyCtxt<'_>, def: ty::WithOptParam<DefId>) -> Steal<Body<'_>> {
+    let def = def.expect_local();
 
     // Unsafety check uses the raw mir, so make sure it is run.
-    let _ = tcx.unsafety_check_result(def_id);
+    let _ = tcx.unsafety_check_result(def);
 
-    let mut body = tcx.mir_built(def_id).steal();
+    let mut body = tcx.mir_built(def).steal();
 
-    util::dump_mir(tcx, None, "mir_map", &0, MirSource::item(def_id.to_def_id()), &body, |_, _| {
-        Ok(())
-    });
+    util::dump_mir(
+        tcx,
+        None,
+        "mir_map",
+        &0,
+        MirSource::item(def.did.to_def_id()),
+        &body,
+        |_, _| Ok(()),
+    );
 
     run_passes(
         tcx,
         &mut body,
-        InstanceDef::Item(def_id.to_def_id()),
+        InstanceDef::Item(def.to_global()),
         None,
         MirPhase::Const,
         &[&[
@@ -264,13 +280,13 @@ fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> Steal<Body<'_>> {
 
 fn mir_validated(
     tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
+    def: ty::WithOptParam<LocalDefId>,
 ) -> (Steal<Body<'tcx>>, Steal<IndexVec<Promoted, Body<'tcx>>>) {
     // Ensure that we compute the `mir_const_qualif` for constants at
     // this point, before we steal the mir-const result.
-    let _ = tcx.mir_const_qualif(def_id.to_def_id());
+    let _ = tcx.mir_const_qualif(def.to_global());
 
-    let mut body = tcx.mir_const(def_id.to_def_id()).steal();
+    let mut body = tcx.mir_const(def.to_global()).steal();
 
     let mut required_consts = Vec::new();
     let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts);
@@ -283,7 +299,7 @@ fn mir_validated(
     run_passes(
         tcx,
         &mut body,
-        InstanceDef::Item(def_id.to_def_id()),
+        InstanceDef::Item(def.to_global()),
         None,
         MirPhase::Validated,
         &[&[
@@ -303,17 +319,17 @@ fn mir_validated(
 
 fn mir_drops_elaborated_and_const_checked<'tcx>(
     tcx: TyCtxt<'tcx>,
-    def_id: LocalDefId,
+    def: ty::WithOptParam<LocalDefId>,
 ) -> Steal<Body<'tcx>> {
     // (Mir-)Borrowck uses `mir_validated`, so we have to force it to
     // execute before we can steal.
-    tcx.ensure().mir_borrowck(def_id);
+    tcx.ensure().mir_borrowck(def);
 
-    let (body, _) = tcx.mir_validated(def_id);
+    let (body, _) = tcx.mir_validated(def);
     let mut body = body.steal();
 
-    run_post_borrowck_cleanup_passes(tcx, &mut body, def_id, None);
-    check_consts::post_drop_elaboration::check_live_drops(tcx, def_id, &body);
+    run_post_borrowck_cleanup_passes(tcx, &mut body, def.did, None);
+    check_consts::post_drop_elaboration::check_live_drops(tcx, def.did, &body);
     tcx.alloc_steal_mir(body)
 }
 
@@ -349,7 +365,7 @@ fn run_post_borrowck_cleanup_passes<'tcx>(
     run_passes(
         tcx,
         body,
-        InstanceDef::Item(def_id.to_def_id()),
+        InstanceDef::Item(ty::WithOptParam::dummy(def_id.to_def_id())),
         promoted,
         MirPhase::DropElab,
         &[post_borrowck_cleanup],
@@ -413,7 +429,7 @@ fn run_optimization_passes<'tcx>(
     run_passes(
         tcx,
         body,
-        InstanceDef::Item(def_id.to_def_id()),
+        InstanceDef::Item(ty::WithOptParam::dummy(def_id.to_def_id())),
         promoted,
         MirPhase::Optimized,
         &[
@@ -423,39 +439,39 @@ fn run_optimization_passes<'tcx>(
     );
 }
 
-fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> {
-    if tcx.is_constructor(def_id) {
+fn optimized_mir(tcx: TyCtxt<'_>, def: ty::WithOptParam<DefId>) -> Body<'_> {
+    if tcx.is_constructor(def.did) {
         // There's no reason to run all of the MIR passes on constructors when
         // we can just output the MIR we want directly. This also saves const
         // qualification and borrow checking the trouble of special casing
         // constructors.
-        return shim::build_adt_ctor(tcx, def_id);
+        return shim::build_adt_ctor(tcx, def.did);
     }
 
-    let def_id = def_id.expect_local();
+    let def = def.expect_local();
 
-    let mut body = tcx.mir_drops_elaborated_and_const_checked(def_id).steal();
-    run_optimization_passes(tcx, &mut body, def_id, None);
+    let mut body = tcx.mir_drops_elaborated_and_const_checked(def).steal();
+    run_optimization_passes(tcx, &mut body, def.did, None);
 
     debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");
 
     body
 }
 
-fn promoted_mir(tcx: TyCtxt<'_>, def_id: DefId) -> IndexVec<Promoted, Body<'_>> {
-    if tcx.is_constructor(def_id) {
+fn promoted_mir(tcx: TyCtxt<'_>, def: ty::WithOptParam<DefId>) -> IndexVec<Promoted, Body<'_>> {
+    if tcx.is_constructor(def.did) {
         return IndexVec::new();
     }
 
-    let def_id = def_id.expect_local();
+    let def = def.expect_local();
 
-    tcx.ensure().mir_borrowck(def_id);
-    let (_, promoted) = tcx.mir_validated(def_id);
+    tcx.ensure().mir_borrowck(def);
+    let (_, promoted) = tcx.mir_validated(def);
     let mut promoted = promoted.steal();
 
     for (p, mut body) in promoted.iter_enumerated_mut() {
-        run_post_borrowck_cleanup_passes(tcx, &mut body, def_id, Some(p));
-        run_optimization_passes(tcx, &mut body, def_id, Some(p));
+        run_post_borrowck_cleanup_passes(tcx, &mut body, def.did, Some(p));
+        run_optimization_passes(tcx, &mut body, def.did, Some(p));
     }
 
     debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 8bcbcd79ae60b..f6d6109e98387 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -60,15 +60,15 @@ impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
             return;
         }
 
-        let def_id = src.def_id();
+        let def = src.with_opt_param();
 
         let mut rpo = traversal::reverse_postorder(body);
-        let ccx = ConstCx::new(tcx, def_id.expect_local(), body);
+        let ccx = ConstCx::new(tcx, def.did.expect_local(), body);
         let (temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo);
 
         let promotable_candidates = validate_candidates(&ccx, &temps, &all_candidates);
 
-        let promoted = promote_candidates(def_id, body, tcx, temps, promotable_candidates);
+        let promoted = promote_candidates(def, body, tcx, temps, promotable_candidates);
         self.promoted_fragments.set(promoted);
     }
 }
@@ -936,7 +936,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
 
     fn promote_candidate(
         mut self,
-        def_id: DefId,
+        def: ty::WithOptParam<DefId>,
         candidate: Candidate,
         next_promoted_id: usize,
     ) -> Option<Body<'tcx>> {
@@ -954,8 +954,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                     literal: tcx.mk_const(ty::Const {
                         ty,
                         val: ty::ConstKind::Unevaluated(
-                            def_id,
-                            InternalSubsts::for_item(tcx, def_id, |param, _| {
+                            def,
+                            InternalSubsts::for_item(tcx, def.did, |param, _| {
                                 if let ty::GenericParamDefKind::Lifetime = param.kind {
                                     tcx.lifetimes.re_erased.into()
                                 } else {
@@ -1099,7 +1099,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
 }
 
 pub fn promote_candidates<'tcx>(
-    def_id: DefId,
+    def: ty::WithOptParam<DefId>,
     body: &mut Body<'tcx>,
     tcx: TyCtxt<'tcx>,
     mut temps: IndexVec<Local, TempState>,
@@ -1157,7 +1157,7 @@ pub fn promote_candidates<'tcx>(
         };
 
         //FIXME(oli-obk): having a `maybe_push()` method on `IndexVec` might be nice
-        if let Some(promoted) = promoter.promote_candidate(def_id, candidate, promotions.len()) {
+        if let Some(promoted) = promoter.promote_candidate(def, candidate, promotions.len()) {
             promotions.push(promoted);
         }
     }
diff --git a/src/librustc_mir/util/graphviz.rs b/src/librustc_mir/util/graphviz.rs
index 50193c4a0db7d..d57928d5dc4d7 100644
--- a/src/librustc_mir/util/graphviz.rs
+++ b/src/librustc_mir/util/graphviz.rs
@@ -21,7 +21,7 @@ where
     }
 
     for def_id in def_ids {
-        let body = &tcx.optimized_mir(def_id);
+        let body = &tcx.optimized_mir(tcx.with_opt_param(def_id));
         write_mir_fn_graphviz(tcx, def_id, body, use_subgraphs, w)?;
     }
 
diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs
index 02614044063fc..1da0cad7de64e 100644
--- a/src/librustc_mir/util/pretty.rs
+++ b/src/librustc_mir/util/pretty.rs
@@ -235,7 +235,8 @@ pub fn write_mir_pretty<'tcx>(
 
     let mut first = true;
     for def_id in dump_mir_def_ids(tcx, single) {
-        let body = &tcx.optimized_mir(def_id);
+        let def = ty::WithOptParam::dummy(def_id);
+        let body = &tcx.optimized_mir(def);
 
         if first {
             first = false;
@@ -246,9 +247,9 @@ pub fn write_mir_pretty<'tcx>(
 
         write_mir_fn(tcx, MirSource::item(def_id), body, &mut |_, _| Ok(()), w)?;
 
-        for (i, body) in tcx.promoted_mir(def_id).iter_enumerated() {
+        for (i, body) in tcx.promoted_mir(def).iter_enumerated() {
             writeln!(w)?;
-            let src = MirSource { instance: ty::InstanceDef::Item(def_id), promoted: Some(i) };
+            let src = MirSource { instance: ty::InstanceDef::Item(def), promoted: Some(i) };
             write_mir_fn(tcx, src, body, &mut |_, _| Ok(()), w)?;
         }
     }
diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs
index e2cf1bce733d6..fdc58200b9694 100644
--- a/src/librustc_mir_build/build/mod.rs
+++ b/src/librustc_mir_build/build/mod.rs
@@ -21,13 +21,13 @@ use rustc_target::spec::PanicStrategy;
 
 use super::lints;
 
-crate fn mir_built(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::steal::Steal<Body<'_>> {
-    tcx.alloc_steal_mir(mir_build(tcx, def_id))
+crate fn mir_built(tcx: TyCtxt<'_>, def: ty::WithOptParam<LocalDefId>) -> ty::steal::Steal<Body<'_>> {
+    tcx.alloc_steal_mir(mir_build(tcx, def))
 }
 
 /// Construct the MIR for a given `DefId`.
-fn mir_build(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Body<'_> {
-    let id = tcx.hir().as_local_hir_id(def_id);
+fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptParam<LocalDefId>) -> Body<'_> {
+    let id = tcx.hir().as_local_hir_id(def.did);
 
     // Figure out what primary body this item has.
     let (body_id, return_ty_span) = match tcx.hir().get(id) {
@@ -57,11 +57,11 @@ fn mir_build(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Body<'_> {
         }) => (*body_id, ty.span),
         Node::AnonConst(hir::AnonConst { body, hir_id, .. }) => (*body, tcx.hir().span(*hir_id)),
 
-        _ => span_bug!(tcx.hir().span(id), "can't build MIR for {:?}", def_id),
+        _ => span_bug!(tcx.hir().span(id), "can't build MIR for {:?}", def),
     };
 
     tcx.infer_ctxt().enter(|infcx| {
-        let cx = Cx::new(&infcx, id);
+        let cx = Cx::new(&infcx, id, def);
         let body = if let Some(ErrorReported) = cx.tables().tainted_by_errors {
             build::construct_error(cx, body_id)
         } else if cx.body_owner_kind.is_fn_or_closure() {
@@ -181,7 +181,7 @@ fn mir_build(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Body<'_> {
             build::construct_const(cx, body_id, return_ty, return_ty_span)
         };
 
-        lints::check(tcx, &body, def_id);
+        lints::check(tcx, &body, def.did);
 
         // The borrow checker will replace all the regions here with its own
         // inference variables. There's no point having non-erased regions here.
diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs
index a1796c9433eac..357afa3cf7922 100644
--- a/src/librustc_mir_build/hair/cx/expr.rs
+++ b/src/librustc_mir_build/hair/cx/expr.rs
@@ -614,7 +614,11 @@ fn make_mirror_unadjusted<'a, 'tcx>(
                             // and not the beginning of discriminants (which is always `0`)
                             let substs = InternalSubsts::identity_for_item(cx.tcx(), did);
                             let lhs = mk_const(cx.tcx().mk_const(ty::Const {
-                                val: ty::ConstKind::Unevaluated(did, substs, None),
+                                val: ty::ConstKind::Unevaluated(
+                                    cx.tcx().with_opt_param(did),
+                                    substs,
+                                    None,
+                                ),
                                 ty: var_ty,
                             }));
                             let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset };
@@ -810,7 +814,7 @@ fn convert_path_expr<'a, 'tcx>(
             debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
             ExprKind::Literal {
                 literal: cx.tcx.mk_const(ty::Const {
-                    val: ty::ConstKind::Unevaluated(def_id, substs, None),
+                    val: ty::ConstKind::Unevaluated(cx.tcx.with_opt_param(def_id), substs, None),
                     ty: cx.tables().node_type(expr.hir_id),
                 }),
                 user_ty,
@@ -868,7 +872,7 @@ fn convert_var<'tcx>(
     let upvar_index = cx
         .tables()
         .closure_captures
-        .get(&cx.body_owner)
+        .get(&cx.body_owner.did.to_def_id())
         .and_then(|upvars| upvars.get_full(&var_hir_id).map(|(i, _, _)| i));
 
     debug!(
@@ -882,10 +886,10 @@ fn convert_var<'tcx>(
         None => ExprKind::VarRef { id: var_hir_id },
 
         Some(upvar_index) => {
-            let closure_def_id = cx.body_owner;
+            let closure_def_id = cx.body_owner.did;
             let upvar_id = ty::UpvarId {
                 var_path: ty::UpvarPath { hir_id: var_hir_id },
-                closure_expr_id: closure_def_id.expect_local(),
+                closure_expr_id: closure_def_id,
             };
             let var_ty = cx.tables().node_type(var_hir_id);
 
@@ -898,7 +902,7 @@ fn convert_var<'tcx>(
             // signature will be &self or &mut self and hence will
             // have a bound region with number 0
             let region = ty::ReFree(ty::FreeRegion {
-                scope: closure_def_id,
+                scope: closure_def_id.to_def_id(),
                 bound_region: ty::BoundRegion::BrAnon(0),
             });
             let region = cx.tcx.mk_region(region);
diff --git a/src/librustc_mir_build/hair/cx/mod.rs b/src/librustc_mir_build/hair/cx/mod.rs
index 46607fd07cdd7..51686b4b13dc0 100644
--- a/src/librustc_mir_build/hair/cx/mod.rs
+++ b/src/librustc_mir_build/hair/cx/mod.rs
@@ -8,7 +8,7 @@ use crate::hair::*;
 use rustc_ast::ast;
 use rustc_ast::attr;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::Node;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::InferCtxt;
@@ -40,7 +40,7 @@ crate struct Cx<'a, 'tcx> {
     constness: hir::Constness,
 
     /// The `DefId` of the owner of this body.
-    body_owner: DefId,
+    body_owner: ty::WithOptParam<LocalDefId>,
 
     /// What kind of body is being compiled.
     crate body_owner_kind: hir::BodyOwnerKind,
@@ -53,10 +53,14 @@ crate struct Cx<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Cx<'a, 'tcx> {
-    crate fn new(infcx: &'a InferCtxt<'a, 'tcx>, src_id: hir::HirId) -> Cx<'a, 'tcx> {
+    crate fn new(
+        infcx: &'a InferCtxt<'a, 'tcx>,
+        src_id: hir::HirId,
+        body_owner: ty::WithOptParam<LocalDefId>,
+    ) -> Cx<'a, 'tcx> {
         let tcx = infcx.tcx;
-        let src_def_id = tcx.hir().local_def_id(src_id);
-        let tables = tcx.typeck_tables_of(src_def_id);
+
+        let tables = tcx.typeck_tables_of(body_owner);
         let body_owner_kind = tcx.hir().body_owner_kind(src_id);
 
         let constness = match body_owner_kind {
@@ -81,12 +85,12 @@ impl<'a, 'tcx> Cx<'a, 'tcx> {
             tcx,
             infcx,
             root_lint_level: src_id,
-            param_env: tcx.param_env(src_def_id),
-            identity_substs: InternalSubsts::identity_for_item(tcx, src_def_id.to_def_id()),
-            region_scope_tree: tcx.region_scope_tree(src_def_id),
+            param_env: tcx.param_env(body_owner.did),
+            identity_substs: InternalSubsts::identity_for_item(tcx, body_owner.did.to_def_id()),
+            region_scope_tree: tcx.region_scope_tree(body_owner.did),
             tables,
             constness,
-            body_owner: src_def_id.to_def_id(),
+            body_owner,
             body_owner_kind,
             check_overflow,
             control_flow_destroyed: Vec::new(),
diff --git a/src/librustc_mir_build/hair/pattern/mod.rs b/src/librustc_mir_build/hair/pattern/mod.rs
index 5c30b2a448c6d..93b2115925400 100644
--- a/src/librustc_mir_build/hair/pattern/mod.rs
+++ b/src/librustc_mir_build/hair/pattern/mod.rs
@@ -801,7 +801,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         // `mir_const_qualif` must be called with the `DefId` of the item where the const is
         // defined, not where it is declared. The difference is significant for associated
         // constants.
-        let mir_structural_match_violation = self.tcx.mir_const_qualif(instance.def_id()).custom_eq;
+        let mir_structural_match_violation =
+            self.tcx.mir_const_qualif(instance.def.with_opt_param()).custom_eq;
         debug!("mir_structural_match_violation({:?}) -> {}", qpath, mir_structural_match_violation);
 
         match self.tcx.const_eval_instance(param_env_reveal_all, instance, Some(span)) {
diff --git a/src/librustc_passes/intrinsicck.rs b/src/librustc_passes/intrinsicck.rs
index c8666ba1fd078..57b141f337d59 100644
--- a/src/librustc_passes/intrinsicck.rs
+++ b/src/librustc_passes/intrinsicck.rs
@@ -400,7 +400,7 @@ impl Visitor<'tcx> for ItemVisitor<'tcx> {
         let owner_def_id = self.tcx.hir().body_owner_def_id(body_id);
         let body = self.tcx.hir().body(body_id);
         let param_env = self.tcx.param_env(owner_def_id.to_def_id());
-        let tables = self.tcx.typeck_tables_of(owner_def_id);
+        let tables = self.tcx.typeck_tables_of(self.tcx.with_opt_param(owner_def_id));
         ExprVisitor { tcx: self.tcx, param_env, tables }.visit_body(body);
         self.visit_body(body);
     }
diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs
index ff5dabd5418c9..8c05c44dc5fa7 100644
--- a/src/librustc_passes/liveness.rs
+++ b/src/librustc_passes/liveness.rs
@@ -670,7 +670,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             exit_ln: ir.add_live_node(ExitNode),
         };
 
-        let tables = ir.tcx.typeck_tables_of(def_id);
+        let tables = ir.tcx.typeck_tables_of(ir.tcx.with_opt_param(def_id));
         let param_env = ir.tcx.param_env(def_id);
 
         let num_live_nodes = ir.num_live_nodes;
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 9e6e7ea962bc3..3d389e7368d6c 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -353,7 +353,11 @@ fn item_tables<'a, 'tcx>(
     empty_tables: &'a ty::TypeckTables<'tcx>,
 ) -> &'a ty::TypeckTables<'tcx> {
     let def_id = tcx.hir().local_def_id(hir_id);
-    if tcx.has_typeck_tables(def_id) { tcx.typeck_tables_of(def_id) } else { empty_tables }
+    if tcx.has_typeck_tables(def_id) {
+        tcx.typeck_tables_of(tcx.with_opt_param(def_id))
+    } else {
+        empty_tables
+    }
 }
 
 fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visibility {
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index e63e31e03c9f0..467e3ad1c45da 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -109,7 +109,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         F: FnOnce(&mut Self),
     {
         let tables = if self.tcx.has_typeck_tables(item_def_id) {
-            self.tcx.typeck_tables_of(item_def_id)
+            self.tcx.typeck_tables_of(self.tcx.with_opt_param(item_def_id))
         } else {
             self.save_ctxt.empty_tables
         };
diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
index 176bd90303ddd..5e96a627617ac 100644
--- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
@@ -1409,7 +1409,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         let tables: &TypeckTables<'tcx> = match &in_progress_tables {
             Some(t) if t.hir_owner.map(|owner| owner.to_def_id()) == Some(generator_did_root) => t,
             _ => {
-                query_tables = self.tcx.typeck_tables_of(generator_did.expect_local());
+                query_tables = self
+                    .tcx
+                    .typeck_tables_of(self.tcx.with_opt_param(generator_did.expect_local()));
                 &query_tables
             }
         };
diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs
index 32ab63458e752..786a230e62299 100644
--- a/src/librustc_trait_selection/traits/fulfill.rs
+++ b/src/librustc_trait_selection/traits/fulfill.rs
@@ -505,10 +505,10 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
                 }
             }
 
-            &ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
+            &ty::PredicateKind::ConstEvaluatable(def, substs) => {
                 match self.selcx.infcx().const_eval_resolve(
                     obligation.param_env,
-                    def_id,
+                    def,
                     substs,
                     None,
                     Some(obligation.cause.span),
@@ -524,10 +524,10 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
                 let stalled_on = &mut pending_obligation.stalled_on;
 
                 let mut evaluate = |c: &'tcx Const<'tcx>| {
-                    if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val {
+                    if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val {
                         match self.selcx.infcx().const_eval_resolve(
                             obligation.param_env,
-                            def_id,
+                            def,
                             substs,
                             promoted,
                             Some(obligation.cause.span),
diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs
index cff5efbfd0fd1..cfbaeade75955 100644
--- a/src/librustc_trait_selection/traits/select/mod.rs
+++ b/src/librustc_trait_selection/traits/select/mod.rs
@@ -489,14 +489,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
             }
 
-            &ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
-                match self.tcx().const_eval_resolve(
-                    obligation.param_env,
-                    def_id,
-                    substs,
-                    None,
-                    None,
-                ) {
+            &ty::PredicateKind::ConstEvaluatable(def, substs) => {
+                match self.tcx().const_eval_resolve(obligation.param_env, def, substs, None, None) {
                     Ok(_) => Ok(EvaluatedToOk),
                     Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig),
                     Err(_) => Ok(EvaluatedToErr),
@@ -507,11 +501,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 debug!("evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", c1, c2);
 
                 let evaluate = |c: &'tcx ty::Const<'tcx>| {
-                    if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val {
+                    if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val {
                         self.infcx
                             .const_eval_resolve(
                                 obligation.param_env,
-                                def_id,
+                                def,
                                 substs,
                                 promoted,
                                 Some(obligation.cause.span),
diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs
index 1825c159ff3fb..12bea5c3b7abe 100644
--- a/src/librustc_trait_selection/traits/wf.rs
+++ b/src/librustc_trait_selection/traits/wf.rs
@@ -116,8 +116,8 @@ pub fn predicate_obligations<'a, 'tcx>(
             wf.compute(data.skip_binder().a.into()); // (*)
             wf.compute(data.skip_binder().b.into()); // (*)
         }
-        &ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
-            let obligations = wf.nominal_obligations(def_id, substs);
+        &ty::PredicateKind::ConstEvaluatable(def, substs) => {
+            let obligations = wf.nominal_obligations(def.did, substs);
             wf.out.extend(obligations);
 
             for arg in substs.iter() {
@@ -359,13 +359,13 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
 
                 GenericArgKind::Const(constant) => {
                     match constant.val {
-                        ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
+                        ty::ConstKind::Unevaluated(def, substs, promoted) => {
                             assert!(promoted.is_none());
 
-                            let obligations = self.nominal_obligations(def_id, substs);
+                            let obligations = self.nominal_obligations(def.did, substs);
                             self.out.extend(obligations);
 
-                            let predicate = ty::PredicateKind::ConstEvaluatable(def_id, substs)
+                            let predicate = ty::PredicateKind::ConstEvaluatable(def, substs)
                                 .to_predicate(self.tcx());
                             let cause = self.cause(traits::MiscObligation);
                             self.out.push(traits::Obligation::new(
diff --git a/src/librustc_ty/instance.rs b/src/librustc_ty/instance.rs
index 0acf769168137..19c591fba7ff6 100644
--- a/src/librustc_ty/instance.rs
+++ b/src/librustc_ty/instance.rs
@@ -12,17 +12,17 @@ use log::debug;
 
 fn resolve_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
-    key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>,
+    key: ty::ParamEnvAnd<'tcx, (ty::WithOptParam<DefId>, SubstsRef<'tcx>)>,
 ) -> Result<Option<Instance<'tcx>>, ErrorReported> {
-    let (param_env, (def_id, substs)) = key.into_parts();
+    let (param_env, (def, substs)) = key.into_parts();
 
-    debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
-    let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
+    debug!("resolve(def={:?}, substs={:?})", def, substs);
+    let result = if let Some(trait_def_id) = tcx.trait_of_item(def.did) {
         debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
-        let item = tcx.associated_item(def_id);
+        let item = tcx.associated_item(def.did);
         resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
     } else {
-        let ty = tcx.type_of(def_id);
+        let ty = tcx.type_of(def.ty_def_id());
         let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, &ty);
 
         let def = match item_type.kind {
@@ -33,7 +33,7 @@ fn resolve_instance<'tcx>(
                 } =>
             {
                 debug!(" => intrinsic");
-                ty::InstanceDef::Intrinsic(def_id)
+                ty::InstanceDef::Intrinsic(def.did)
             }
             ty::FnDef(def_id, substs) if Some(def_id) == tcx.lang_items().drop_in_place_fn() => {
                 let ty = substs.type_at(0);
@@ -53,12 +53,12 @@ fn resolve_instance<'tcx>(
             }
             _ => {
                 debug!(" => free item");
-                ty::InstanceDef::Item(def_id)
+                ty::InstanceDef::Item(def)
             }
         };
         Ok(Some(Instance { def, substs }))
     };
-    debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, substs, result);
+    debug!("resolve(def={:?}, substs={:?}) = {:?}", def, substs, result);
     result
 }
 
@@ -182,7 +182,7 @@ fn resolve_associated_item<'tcx>(
             Some(ty::Instance::new(leaf_def.item.def_id, substs))
         }
         traits::ImplSourceGenerator(generator_data) => Some(Instance {
-            def: ty::InstanceDef::Item(generator_data.generator_def_id),
+            def: ty::InstanceDef::Item(ty::WithOptParam::dummy(generator_data.generator_def_id)),
             substs: generator_data.substs,
         }),
         traits::ImplSourceClosure(closure_data) => {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 1b08bf2fc7710..9969f4857416b 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -886,8 +886,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     }
                 }
                 (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
-                    let ct_def_id = tcx.hir().local_def_id(ct.value.hir_id);
-                    ty::Const::from_anon_const(tcx, ct_def_id).into()
+                    ty::Const::const_arg_from_anon_const(
+                        tcx,
+                        ty::WithOptParam {
+                            did: tcx.hir().local_def_id(ct.value.hir_id),
+                            param_did: Some(param.def_id),
+                        },
+                    )
+                    .into()
                 }
                 _ => unreachable!(),
             },
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 1c3d23a3a241f..0ca85b5165ea0 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -325,7 +325,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                 }
                 (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => self.to_ty(ty).into(),
                 (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
-                    self.to_const(&ct.value).into()
+                    self.const_arg_to_const(&ct.value, param.def_id).into()
                 }
                 _ => unreachable!(),
             },
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 0325782e69d51..d009a4f591eea 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -737,6 +737,11 @@ pub fn check_wf_new(tcx: TyCtxt<'_>) {
     tcx.hir().krate().par_visit_all_item_likes(&visit);
 }
 
+/// Computes `const_param_of` for all relevant `DefId`s in the current crate.
+pub fn compute_const_params_of(tcx: TyCtxt<'_>) {
+    tcx.par_body_owners(|body_owner_def_id| tcx.ensure().const_param_of(body_owner_def_id))
+}
+
 fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: DefId) {
     tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx });
 }
@@ -744,7 +749,7 @@ fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: DefId) {
 fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) {
     debug_assert!(crate_num == LOCAL_CRATE);
     tcx.par_body_owners(|body_owner_def_id| {
-        tcx.ensure().typeck_tables_of(body_owner_def_id);
+        tcx.ensure().typeck_tables_of(tcx.with_opt_param(body_owner_def_id));
     });
 }
 
@@ -841,7 +846,7 @@ fn has_typeck_tables(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 }
 
 fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
-    &*tcx.typeck_tables_of(def_id).used_trait_imports
+    &*tcx.typeck_tables_of(ty::WithOptParam::dummy(def_id)).used_trait_imports
 }
 
 /// Inspects the substs of opaque types, replacing any inference variables
@@ -955,9 +960,11 @@ where
     val.fold_with(&mut FixupFolder { tcx })
 }
 
-fn typeck_tables_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckTables<'tcx> {
-    let fallback = move || tcx.type_of(def_id.to_def_id());
-    typeck_tables_of_with_fallback(tcx, def_id, fallback)
+fn typeck_tables_of<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def: ty::WithOptParam<LocalDefId>,
+) -> &ty::TypeckTables<'tcx> {
+    typeck_tables_of_with_fallback(tcx, def.did, move || tcx.type_of(def.ty_def_id()))
 }
 
 /// Used only to get `TypeckTables` for type inference during error recovery.
@@ -982,7 +989,7 @@ fn typeck_tables_of_with_fallback<'tcx>(
     // as they are part of the same "inference environment".
     let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
     if outer_def_id != def_id {
-        return tcx.typeck_tables_of(outer_def_id);
+        return tcx.typeck_tables_of(tcx.with_opt_param(outer_def_id));
     }
 
     let id = tcx.hir().as_local_hir_id(def_id);
@@ -1744,7 +1751,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
 
     let mut label = false;
     if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) {
-        let tables = tcx.typeck_tables_of(tcx.hir().local_def_id(hir_id));
+        let tables = tcx.typeck_tables_of(ty::WithOptParam::dummy(tcx.hir().local_def_id(hir_id)));
         if visitor
             .returns
             .iter()
@@ -1847,8 +1854,9 @@ fn binding_opaque_type_cycle_error(
                 ..
             }) => {
                 let hir_id = tcx.hir().as_local_hir_id(def_id);
-                let tables =
-                    tcx.typeck_tables_of(tcx.hir().local_def_id(tcx.hir().get_parent_item(hir_id)));
+                let tables = tcx.typeck_tables_of(ty::WithOptParam::dummy(
+                    tcx.hir().local_def_id(tcx.hir().get_parent_item(hir_id)),
+                ));
                 if let Some(ty) = tables.node_type_opt(expr.hir_id) {
                     err.span_label(
                         expr.span,
@@ -1917,11 +1925,11 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
         // Consts can play a role in type-checking, so they are included here.
         hir::ItemKind::Static(..) => {
             let def_id = tcx.hir().local_def_id(it.hir_id);
-            tcx.ensure().typeck_tables_of(def_id);
+            tcx.ensure().typeck_tables_of(tcx.with_opt_param(def_id));
             maybe_check_static_with_link_section(tcx, def_id, it.span);
         }
         hir::ItemKind::Const(..) => {
-            tcx.ensure().typeck_tables_of(tcx.hir().local_def_id(it.hir_id));
+            tcx.ensure().typeck_tables_of(tcx.with_opt_param(tcx.hir().local_def_id(it.hir_id)));
         }
         hir::ItemKind::Enum(ref enum_definition, _) => {
             check_enum(tcx, it.span, &enum_definition.variants, it.hir_id);
@@ -2832,7 +2840,7 @@ pub fn check_enum<'tcx>(
 
     for v in vs {
         if let Some(ref e) = v.disr_expr {
-            tcx.ensure().typeck_tables_of(tcx.hir().local_def_id(e.hir_id));
+            tcx.ensure().typeck_tables_of(tcx.with_opt_param(tcx.hir().local_def_id(e.hir_id)));
         }
     }
 
@@ -3531,6 +3539,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ty
     }
 
+    pub fn const_arg_to_const(
+        &self,
+        ast_c: &hir::AnonConst,
+        param_def_id: DefId,
+    ) -> &'tcx ty::Const<'tcx> {
+        let const_def = ty::WithOptParam {
+            did: self.tcx.hir().local_def_id(ast_c.hir_id),
+            param_did: Some(param_def_id),
+        };
+        let c = ty::Const::const_arg_from_anon_const(self.tcx, const_def);
+        self.register_wf_obligation(
+            c.into(),
+            self.tcx.hir().span(ast_c.hir_id),
+            ObligationCauseCode::MiscObligation,
+        );
+        c
+    }
+
     pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
         let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
         let c = ty::Const::from_anon_const(self.tcx, const_def_id);
@@ -5655,7 +5681,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         self.to_ty(ty).into()
                     }
                     (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
-                        self.to_const(&ct.value).into()
+                        self.const_arg_to_const(&ct.value, param.def_id).into()
                     }
                     _ => unreachable!(),
                 },
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index d1a86a7ee89a8..20736baf19119 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -422,8 +422,11 @@ fn check_type_defn<'tcx, F>(
                 fcx.register_predicate(traits::Obligation::new(
                     cause,
                     fcx.param_env,
-                    ty::PredicateKind::ConstEvaluatable(discr_def_id.to_def_id(), discr_substs)
-                        .to_predicate(fcx.tcx),
+                    ty::PredicateKind::ConstEvaluatable(
+                        fcx.tcx.with_opt_param(discr_def_id.to_def_id()),
+                        discr_substs,
+                    )
+                    .to_predicate(fcx.tcx),
                 ));
             }
         }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 054165f2b0977..5f068ff06a77b 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -64,6 +64,7 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: DefId) {
 
 pub fn provide(providers: &mut Providers<'_>) {
     *providers = Providers {
+        const_param_of: type_of::const_param_of,
         type_of: type_of::type_of,
         generics_of,
         predicates_of,
@@ -1459,7 +1460,9 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
         | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), ident, .. }) => {
             match get_infer_ret_ty(&sig.decl.output) {
                 Some(ty) => {
-                    let fn_sig = tcx.typeck_tables_of(def_id).liberated_fn_sigs()[hir_id];
+                    let fn_sig = tcx
+                        .typeck_tables_of(tcx.with_opt_param(def_id))
+                        .liberated_fn_sigs()[hir_id];
                     let mut visitor = PlaceholderHirTyCollector::default();
                     visitor.visit_ty(ty);
                     let mut diag = bad_placeholder_type(tcx, visitor.0);
diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs
index 3dd9c9c5c39db..c2d2300eaae6f 100644
--- a/src/librustc_typeck/collect/type_of.rs
+++ b/src/librustc_typeck/collect/type_of.rs
@@ -17,6 +17,126 @@ use rustc_trait_selection::traits;
 use super::ItemCtxt;
 use super::{bad_placeholder_type, is_suggestable_infer_ty};
 
+/// Computes the relevant generic parameter for a potential generic const argument.
+///
+/// This should be called using the query `tcx.const_param_of`.
+pub(super) fn const_param_of(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
+    use hir::*;
+
+    // We can just exit here, as `const_param_of` is called for
+    // all generic arguments, meaning that we would return `None` anyways
+    // if `const_param_of` is not cached
+    let hir_id = tcx.hir().as_local_hir_id(def_id.as_local()?);
+
+    if let Node::AnonConst(_) = tcx.hir().get(hir_id) {
+        let parent_node_id = tcx.hir().get_parent_node(hir_id);
+        let parent_node = tcx.hir().get(parent_node_id);
+
+        match parent_node {
+            Node::Expr(&Expr {
+                kind:
+                    ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
+                ..
+            }) => {
+                let body_owner = tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
+                let tables = tcx.typeck_tables_of(tcx.with_opt_param(body_owner));
+                // This may fail in case the method/path does not actually exist.
+                // As there is no relevant param for `def_id`, we simply return
+                // `None` here.
+                let type_dependent_def = tables.type_dependent_def_id(parent_node_id)?;
+                let idx = segment
+                    .args
+                    .and_then(|args| {
+                        args.args
+                            .iter()
+                            .filter(|arg| arg.is_const())
+                            .position(|arg| arg.id() == hir_id)
+                    })
+                    .unwrap_or_else(|| {
+                        bug!("no arg matching AnonConst in segment");
+                    });
+
+                tcx.generics_of(type_dependent_def)
+                    .params
+                    .iter()
+                    .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const))
+                    .nth(idx)
+                    .map(|param| param.def_id)
+            }
+
+            Node::Ty(&Ty { kind: TyKind::Path(_), .. })
+            | Node::Expr(&Expr { kind: ExprKind::Struct(..), .. })
+            | Node::Expr(&Expr { kind: ExprKind::Path(_), .. })
+            | Node::TraitRef(..) => {
+                let path = match parent_node {
+                    Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
+                    | Node::TraitRef(&TraitRef { path, .. }) => &*path,
+                    Node::Expr(&Expr {
+                        kind:
+                            ExprKind::Path(QPath::Resolved(_, path))
+                            | ExprKind::Struct(&QPath::Resolved(_, path), ..),
+                        ..
+                    }) => {
+                        let body_owner =
+                            tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
+                        let _tables = tcx.typeck_tables_of(tcx.with_opt_param(body_owner));
+                        &*path
+                    }
+                    _ => span_bug!(DUMMY_SP, "unexpected const parent path {:?}", parent_node),
+                };
+
+                // We've encountered an `AnonConst` in some path, so we need to
+                // figure out which generic parameter it corresponds to and return
+                // the relevant type.
+
+                let (arg_index, segment) = path
+                    .segments
+                    .iter()
+                    .filter_map(|seg| seg.args.map(|args| (args.args, seg)))
+                    .find_map(|(args, seg)| {
+                        args.iter()
+                            .filter(|arg| arg.is_const())
+                            .position(|arg| arg.id() == hir_id)
+                            .map(|index| (index, seg))
+                    })
+                    .unwrap_or_else(|| {
+                        bug!("no arg matching AnonConst in path");
+                    });
+
+                // Try to use the segment resolution if it is valid, otherwise we
+                // default to the path resolution.
+                let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res);
+                let generics = match res {
+                    Res::Def(DefKind::Ctor(..), def_id) => {
+                        tcx.generics_of(tcx.parent(def_id).unwrap())
+                    }
+                    Res::Def(_, def_id) => tcx.generics_of(def_id),
+                    Res::Err => {
+                        tcx.sess.delay_span_bug(tcx.def_span(def_id), "anon const with Res::Err");
+                        return None;
+                    }
+                    _ => span_bug!(
+                        DUMMY_SP,
+                        "unexpected anon const res {:?} in path: {:?}",
+                        res,
+                        path,
+                    ),
+                };
+
+                generics
+                    .params
+                    .iter()
+                    .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const))
+                    .nth(arg_index)
+                    .map(|param| param.def_id)
+            }
+            _ => None,
+        }
+    } else {
+        None
+    }
+}
+
 pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
     use rustc_hir::*;
 
@@ -108,7 +228,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                 // Opaque types desugared from `impl Trait`.
                 ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: Some(owner), .. }) => {
                     let concrete_ty = tcx
-                        .mir_borrowck(owner.expect_local())
+                        .mir_borrowck(tcx.with_opt_param(owner.expect_local()))
                         .concrete_opaque_types
                         .get(&def_id)
                         .map(|opaque| opaque.concrete_type)
@@ -120,8 +240,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                                     owner, def_id,
                                 ),
                             );
-                            if let Some(ErrorReported) =
-                                tcx.typeck_tables_of(owner.expect_local()).tainted_by_errors
+                            if let Some(ErrorReported) = tcx
+                                .typeck_tables_of(tcx.with_opt_param(owner.expect_local()))
+                                .tainted_by_errors
                             {
                                 // Some error in the
                                 // owner fn prevented us from populating
@@ -187,6 +308,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
         }
 
         Node::AnonConst(_) => {
+            if let Some(param) = tcx.const_param_of(def_id) {
+                // We defer to `type_of` of the corresponding parameter
+                // for generic arguments.
+                return tcx.type_of(param);
+            }
+
             let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
             match parent_node {
                 Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
@@ -203,94 +330,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     .discr_type()
                     .to_ty(tcx),
 
-                Node::Ty(&Ty { kind: TyKind::Path(_), .. })
-                | Node::Expr(&Expr { kind: ExprKind::Struct(..) | ExprKind::Path(_), .. })
-                | Node::TraitRef(..) => {
-                    let path = match parent_node {
-                        Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
-                        | Node::Expr(&Expr {
-                            kind:
-                                ExprKind::Path(QPath::Resolved(_, path))
-                                | ExprKind::Struct(&QPath::Resolved(_, path), ..),
-                            ..
-                        })
-                        | Node::TraitRef(&TraitRef { path, .. }) => &*path,
-                        _ => {
-                            return tcx.ty_error_with_message(
-                                DUMMY_SP,
-                                &format!("unexpected const parent path {:?}", parent_node),
-                            );
-                        }
-                    };
-
-                    // We've encountered an `AnonConst` in some path, so we need to
-                    // figure out which generic parameter it corresponds to and return
-                    // the relevant type.
-
-                    let (arg_index, segment) = path
-                        .segments
-                        .iter()
-                        .filter_map(|seg| seg.args.as_ref().map(|args| (args.args, seg)))
-                        .find_map(|(args, seg)| {
-                            args.iter()
-                                .filter(|arg| arg.is_const())
-                                .enumerate()
-                                .filter(|(_, arg)| arg.id() == hir_id)
-                                .map(|(index, _)| (index, seg))
-                                .next()
-                        })
-                        .unwrap_or_else(|| {
-                            bug!("no arg matching AnonConst in path");
-                        });
-
-                    // Try to use the segment resolution if it is valid, otherwise we
-                    // default to the path resolution.
-                    let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res);
-                    let generics = match res {
-                        Res::Def(DefKind::Ctor(..), def_id) => {
-                            tcx.generics_of(tcx.parent(def_id).unwrap())
-                        }
-                        Res::Def(_, def_id) => tcx.generics_of(def_id),
-                        res => {
-                            return tcx.ty_error_with_message(
-                                DUMMY_SP,
-                                &format!(
-                                    "unexpected anon const res {:?} in path: {:?}",
-                                    res, path,
-                                ),
-                                );
-                        }
-                    };
-
-                    let ty = generics
-                        .params
-                        .iter()
-                        .filter(|param| {
-                            if let ty::GenericParamDefKind::Const = param.kind {
-                                true
-                            } else {
-                                false
-                            }
-                        })
-                        .nth(arg_index)
-                        .map(|param| tcx.type_of(param.def_id));
-
-                    if let Some(ty) = ty {
-                        ty
-                    } else {
-                        // This is no generic parameter associated with the arg. This is
-                        // probably from an extra arg where one is not needed.
-                        tcx.ty_error_with_message(
-                            DUMMY_SP,
-                            &format!(
-                                "missing generic parameter for `AnonConst`, \
-                                 parent: {:?}, res: {:?}",
-                                parent_node, res
-                            ),
-                        )
-                    }
-                }
-
                 x => tcx.ty_error_with_message(
                     DUMMY_SP,
                     &format!("unexpected const parent in type_of_def_id(): {:?}", x),
@@ -396,7 +435,12 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
             }
             // Calling `mir_borrowck` can lead to cycle errors through
             // const-checking, avoid calling it if we don't have to.
-            if !self.tcx.typeck_tables_of(def_id).concrete_opaque_types.contains_key(&self.def_id) {
+            if !self
+                .tcx
+                .typeck_tables_of(self.tcx.with_opt_param(def_id))
+                .concrete_opaque_types
+                .contains_key(&self.def_id)
+            {
                 debug!(
                     "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`",
                     self.def_id, def_id,
@@ -404,7 +448,11 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
                 return;
             }
             // Use borrowck to get the type with unerased regions.
-            let ty = self.tcx.mir_borrowck(def_id).concrete_opaque_types.get(&self.def_id);
+            let ty = self
+                .tcx
+                .mir_borrowck(self.tcx.with_opt_param(def_id))
+                .concrete_opaque_types
+                .get(&self.def_id);
             if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty {
                 debug!(
                     "find_opaque_ty_constraints: found constraint for `{:?}` at `{:?}`: {:?}",
@@ -580,7 +628,7 @@ fn let_position_impl_trait_type(tcx: TyCtxt<'_>, opaque_ty_id: LocalDefId) -> Ty
 
     let opaque_ty_def_id = opaque_ty_id.to_def_id();
 
-    let owner_tables = tcx.typeck_tables_of(scope_def_id);
+    let owner_tables = tcx.typeck_tables_of(tcx.with_opt_param(scope_def_id));
     let concrete_ty = owner_tables
         .concrete_opaque_types
         .get(&opaque_ty_def_id)
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 8d8a1b4d96761..118c534860d69 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -364,6 +364,8 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> {
 
     tcx.sess.time("item_bodies_checking", || tcx.typeck_item_bodies(LOCAL_CRATE));
 
+    tcx.sess.time("compute_const_params_of", || check::compute_const_params_of(tcx));
+
     check_unused::check_crate(tcx);
     check_for_entry_fn(tcx);
 
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index c4e4802db6c07..faad619e59047 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -466,12 +466,12 @@ pub fn name_from_pat(p: &hir::Pat) -> String {
 
 pub fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String {
     match n.val {
-        ty::ConstKind::Unevaluated(def_id, _, promoted) => {
-            let mut s = if let Some(def_id) = def_id.as_local() {
+        ty::ConstKind::Unevaluated(def, _, promoted) => {
+            let mut s = if let Some(def_id) = def.did.as_local() {
                 let hir_id = cx.tcx.hir().as_local_hir_id(def_id);
                 print_const_expr(cx, cx.tcx.hir().body_owned_by(hir_id))
             } else {
-                inline::print_inlined_const(cx, def_id)
+                inline::print_inlined_const(cx, def.did)
             };
             if let Some(promoted) = promoted {
                 s.push_str(&format!("::{:?}", promoted))
diff --git a/src/test/mir-opt/const-promotion-extern-static/rustc.BAR.PromoteTemps.diff b/src/test/mir-opt/const-promotion-extern-static/rustc.BAR.PromoteTemps.diff
index 5c192979a8696..a39ad96739205 100644
--- a/src/test/mir-opt/const-promotion-extern-static/rustc.BAR.PromoteTemps.diff
+++ b/src/test/mir-opt/const-promotion-extern-static/rustc.BAR.PromoteTemps.diff
@@ -22,7 +22,7 @@
 -                                          // + ty: &i32
 -                                          // + val: Value(Scalar(alloc0))
 +                                          // + ty: &[&i32; 1]
-+                                          // + val: Unevaluated(DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), [], Some(promoted[0]))
++                                          // + val: Unevaluated(WithOptParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
 -                                          // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34
 -                                          // + literal: Const { ty: &i32, val: Value(Scalar(alloc0)) }
@@ -30,7 +30,7 @@
 -         _3 = [move _4];                  // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
 -         _2 = &_3;                        // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
 +                                          // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:35
-+                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), [], Some(promoted[0])) }
++                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), param_did: None }, [], Some(promoted[0])) }
 +         _2 = &(*_6);                     // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
           _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
           _0 = const core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44
diff --git a/src/test/mir-opt/const-promotion-extern-static/rustc.FOO.PromoteTemps.diff b/src/test/mir-opt/const-promotion-extern-static/rustc.FOO.PromoteTemps.diff
index 649cea6493e45..e9ca064129947 100644
--- a/src/test/mir-opt/const-promotion-extern-static/rustc.FOO.PromoteTemps.diff
+++ b/src/test/mir-opt/const-promotion-extern-static/rustc.FOO.PromoteTemps.diff
@@ -24,7 +24,7 @@
 -                                          // + ty: &i32
 -                                          // + val: Value(Scalar(alloc2))
 +                                          // + ty: &[&i32; 1]
-+                                          // + val: Unevaluated(DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), [], Some(promoted[0]))
++                                          // + val: Unevaluated(WithOptParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
 -                                          // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43
 -                                          // + literal: Const { ty: &i32, val: Value(Scalar(alloc2)) }
@@ -32,7 +32,7 @@
 -         _3 = [move _4];                  // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
 -         _2 = &_3;                        // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
 +                                          // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:46
-+                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), [], Some(promoted[0])) }
++                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), param_did: None }, [], Some(promoted[0])) }
 +         _2 = &(*_6);                     // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
           _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
           _0 = const core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55
diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff
index 7ceec94d81e76..077854554088a 100644
--- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff
@@ -28,10 +28,10 @@
           _9 = const main::promoted[0];    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
                                            // ty::Const
                                            // + ty: &[i32; 3]
-                                           // + val: Unevaluated(DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), [], Some(promoted[0]))
+                                           // + val: Unevaluated(WithOptParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
-                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), [], Some(promoted[0])) }
+                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(WithOptParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), param_did: None }, [], Some(promoted[0])) }
           _3 = _9;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
           _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff
index 483a6f232ef79..022c97fb3e2ca 100644
--- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff
@@ -28,10 +28,10 @@
           _9 = const main::promoted[0];    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
                                            // ty::Const
                                            // + ty: &[i32; 3]
-                                           // + val: Unevaluated(DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), [], Some(promoted[0]))
+                                           // + val: Unevaluated(WithOptParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
-                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), [], Some(promoted[0])) }
+                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(WithOptParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), param_did: None }, [], Some(promoted[0])) }
           _3 = _9;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
           _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully/rustc.main.ConstProp.diff
index 6c5fe7454b4ed..b09bbead4105d 100644
--- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully/rustc.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully/rustc.main.ConstProp.diff
@@ -19,10 +19,10 @@
           _3 = const main::FOO;            // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
                                            // ty::Const
                                            // + ty: &i32
-                                           // + val: Unevaluated(DefId(0:5 ~ const_prop_fails_gracefully[317d]::main[0]::FOO[0]), [], None)
+                                           // + val: Unevaluated(WithOptParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main[0]::FOO[0]), param_did: None }, [], None)
                                            // mir::Constant
                                            // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
-                                           // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:5 ~ const_prop_fails_gracefully[317d]::main[0]::FOO[0]), [], None) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(WithOptParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main[0]::FOO[0]), param_did: None }, [], None) }
           _2 = &raw const (*_3);           // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
           _1 = move _2 as usize (Misc);    // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39
           StorageDead(_2);                 // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39
diff --git a/src/test/mir-opt/const_prop/control-flow-simplification/rustc.hello.ConstProp.diff b/src/test/mir-opt/const_prop/control-flow-simplification/rustc.hello.ConstProp.diff
index b4d1f087391f3..d8be755632feb 100644
--- a/src/test/mir-opt/const_prop/control-flow-simplification/rustc.hello.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/control-flow-simplification/rustc.hello.ConstProp.diff
@@ -12,11 +12,11 @@
 +         _1 = const false;                // scope 0 at $DIR/control-flow-simplification.rs:12:8: 12:21
                                            // ty::Const
                                            // + ty: bool
--                                          // + val: Unevaluated(DefId(0:4 ~ control_flow_simplification[317d]::NeedsDrop[0]::NEEDS[0]), [bool], None)
+-                                          // + val: Unevaluated(WithOptParam { did: DefId(0:4 ~ control_flow_simplification[317d]::NeedsDrop[0]::NEEDS[0]), param_did: None }, [bool], None)
 +                                          // + val: Value(Scalar(0x00))
                                            // mir::Constant
                                            // + span: $DIR/control-flow-simplification.rs:12:8: 12:21
--                                          // + literal: Const { ty: bool, val: Unevaluated(DefId(0:4 ~ control_flow_simplification[317d]::NeedsDrop[0]::NEEDS[0]), [bool], None) }
+-                                          // + literal: Const { ty: bool, val: Unevaluated(WithOptParam { did: DefId(0:4 ~ control_flow_simplification[317d]::NeedsDrop[0]::NEEDS[0]), param_did: None }, [bool], None) }
 -         switchInt(_1) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/control-flow-simplification.rs:12:5: 14:6
 +                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
 +         switchInt(const false) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/control-flow-simplification.rs:12:5: 14:6
diff --git a/src/test/mir-opt/const_prop/ref_deref/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref/rustc.main.ConstProp.diff
index dcd3d4019811e..2c8fe3e63b28f 100644
--- a/src/test/mir-opt/const_prop/ref_deref/rustc.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/ref_deref/rustc.main.ConstProp.diff
@@ -14,10 +14,10 @@
           _4 = const main::promoted[0];    // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
                                            // ty::Const
                                            // + ty: &i32
-                                           // + val: Unevaluated(DefId(0:3 ~ ref_deref[317d]::main[0]), [], Some(promoted[0]))
+                                           // + val: Unevaluated(WithOptParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/ref_deref.rs:5:6: 5:10
-                                           // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:3 ~ ref_deref[317d]::main[0]), [], Some(promoted[0])) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(WithOptParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), param_did: None }, [], Some(promoted[0])) }
           _2 = _4;                         // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
 -         _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
 +         _1 = const 4i32;                 // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
diff --git a/src/test/mir-opt/const_prop/ref_deref/rustc.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref/rustc.main.PromoteTemps.diff
index ef696f1ab8052..f042b5319add6 100644
--- a/src/test/mir-opt/const_prop/ref_deref/rustc.main.PromoteTemps.diff
+++ b/src/test/mir-opt/const_prop/ref_deref/rustc.main.PromoteTemps.diff
@@ -18,13 +18,13 @@
 -                                          // + ty: i32
 -                                          // + val: Value(Scalar(0x00000004))
 +                                          // + ty: &i32
-+                                          // + val: Unevaluated(DefId(0:3 ~ ref_deref[317d]::main[0]), [], Some(promoted[0]))
++                                          // + val: Unevaluated(WithOptParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
 -                                          // + span: $DIR/ref_deref.rs:5:8: 5:9
 -                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000004)) }
 -         _2 = &_3;                        // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
 +                                          // + span: $DIR/ref_deref.rs:5:6: 5:10
-+                                          // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:3 ~ ref_deref[317d]::main[0]), [], Some(promoted[0])) }
++                                          // + literal: Const { ty: &i32, val: Unevaluated(WithOptParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), param_did: None }, [], Some(promoted[0])) }
 +         _2 = &(*_4);                     // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
 -         StorageDead(_3);                 // scope 0 at $DIR/ref_deref.rs:5:10: 5:11
diff --git a/src/test/mir-opt/const_prop/ref_deref_project/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project/rustc.main.ConstProp.diff
index dd2f5bd906428..7ce4635eeb588 100644
--- a/src/test/mir-opt/const_prop/ref_deref_project/rustc.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/ref_deref_project/rustc.main.ConstProp.diff
@@ -14,10 +14,10 @@
           _4 = const main::promoted[0];    // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
                                            // ty::Const
                                            // + ty: &(i32, i32)
-                                           // + val: Unevaluated(DefId(0:3 ~ ref_deref_project[317d]::main[0]), [], Some(promoted[0]))
+                                           // + val: Unevaluated(WithOptParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/ref_deref_project.rs:5:6: 5:17
-                                           // + literal: Const { ty: &(i32, i32), val: Unevaluated(DefId(0:3 ~ ref_deref_project[317d]::main[0]), [], Some(promoted[0])) }
+                                           // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), param_did: None }, [], Some(promoted[0])) }
           _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
           StorageDead(_2);                 // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
diff --git a/src/test/mir-opt/const_prop/ref_deref_project/rustc.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref_project/rustc.main.PromoteTemps.diff
index 7f23f5ea7a69a..60b784f3ac37b 100644
--- a/src/test/mir-opt/const_prop/ref_deref_project/rustc.main.PromoteTemps.diff
+++ b/src/test/mir-opt/const_prop/ref_deref_project/rustc.main.PromoteTemps.diff
@@ -18,7 +18,7 @@
 -                                          // + ty: i32
 -                                          // + val: Value(Scalar(0x00000004))
 +                                          // + ty: &(i32, i32)
-+                                          // + val: Unevaluated(DefId(0:3 ~ ref_deref_project[317d]::main[0]), [], Some(promoted[0]))
++                                          // + val: Unevaluated(WithOptParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
 -                                          // + span: $DIR/ref_deref_project.rs:5:9: 5:10
 -                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000004)) }
@@ -30,7 +30,7 @@
 -                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
 -         _2 = &(_3.1: i32);               // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
 +                                          // + span: $DIR/ref_deref_project.rs:5:6: 5:17
-+                                          // + literal: Const { ty: &(i32, i32), val: Unevaluated(DefId(0:3 ~ ref_deref_project[317d]::main[0]), [], Some(promoted[0])) }
++                                          // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), param_did: None }, [], Some(promoted[0])) }
 +         _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
 -         StorageDead(_3);                 // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
diff --git a/src/test/mir-opt/const_prop/slice_len/32bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/slice_len/32bit/rustc.main.ConstProp.diff
index 9471dbef410d1..5c7ad17739891 100644
--- a/src/test/mir-opt/const_prop/slice_len/32bit/rustc.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/slice_len/32bit/rustc.main.ConstProp.diff
@@ -21,10 +21,10 @@
           _9 = const main::promoted[0];    // scope 0 at $DIR/slice_len.rs:5:6: 5:19
                                            // ty::Const
                                            // + ty: &[u32; 3]
-                                           // + val: Unevaluated(DefId(0:3 ~ slice_len[317d]::main[0]), [], Some(promoted[0]))
+                                           // + val: Unevaluated(WithOptParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/slice_len.rs:5:6: 5:19
-                                           // + literal: Const { ty: &[u32; 3], val: Unevaluated(DefId(0:3 ~ slice_len[317d]::main[0]), [], Some(promoted[0])) }
+                                           // + literal: Const { ty: &[u32; 3], val: Unevaluated(WithOptParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), param_did: None }, [], Some(promoted[0])) }
           _4 = _9;                         // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           _3 = _4;                         // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19
diff --git a/src/test/mir-opt/const_prop/slice_len/64bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/slice_len/64bit/rustc.main.ConstProp.diff
index 3ae88e0d79863..a48a065d18854 100644
--- a/src/test/mir-opt/const_prop/slice_len/64bit/rustc.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/slice_len/64bit/rustc.main.ConstProp.diff
@@ -21,10 +21,10 @@
           _9 = const main::promoted[0];    // scope 0 at $DIR/slice_len.rs:5:6: 5:19
                                            // ty::Const
                                            // + ty: &[u32; 3]
-                                           // + val: Unevaluated(DefId(0:3 ~ slice_len[317d]::main[0]), [], Some(promoted[0]))
+                                           // + val: Unevaluated(WithOptParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), param_did: None }, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/slice_len.rs:5:6: 5:19
-                                           // + literal: Const { ty: &[u32; 3], val: Unevaluated(DefId(0:3 ~ slice_len[317d]::main[0]), [], Some(promoted[0])) }
+                                           // + literal: Const { ty: &[u32; 3], val: Unevaluated(WithOptParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), param_did: None }, [], Some(promoted[0])) }
           _4 = _9;                         // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           _3 = _4;                         // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19
diff --git a/src/test/mir-opt/inline/inline-retag/rustc.bar.Inline.after.mir b/src/test/mir-opt/inline/inline-retag/rustc.bar.Inline.after.mir
index e83cc92eb43ef..2149200cefb9c 100644
--- a/src/test/mir-opt/inline/inline-retag/rustc.bar.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline-retag/rustc.bar.Inline.after.mir
@@ -38,10 +38,10 @@ fn bar() -> bool {
         _10 = const bar::promoted[1];    // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
                                          // ty::Const
                                          // + ty: &i32
-                                         // + val: Unevaluated(DefId(0:4 ~ inline_retag[317d]::bar[0]), [], Some(promoted[1]))
+                                         // + val: Unevaluated(WithOptParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), param_did: None }, [], Some(promoted[1]))
                                          // mir::Constant
                                          // + span: $DIR/inline-retag.rs:12:7: 12:9
-                                         // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:4 ~ inline_retag[317d]::bar[0]), [], Some(promoted[1])) }
+                                         // + literal: Const { ty: &i32, val: Unevaluated(WithOptParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), param_did: None }, [], Some(promoted[1])) }
         Retag(_10);                      // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
         _4 = &(*_10);                    // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
         Retag(_4);                       // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
@@ -52,10 +52,10 @@ fn bar() -> bool {
         _9 = const bar::promoted[0];     // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
                                          // ty::Const
                                          // + ty: &i32
-                                         // + val: Unevaluated(DefId(0:4 ~ inline_retag[317d]::bar[0]), [], Some(promoted[0]))
+                                         // + val: Unevaluated(WithOptParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), param_did: None }, [], Some(promoted[0]))
                                          // mir::Constant
                                          // + span: $DIR/inline-retag.rs:12:11: 12:14
-                                         // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:4 ~ inline_retag[317d]::bar[0]), [], Some(promoted[0])) }
+                                         // + literal: Const { ty: &i32, val: Unevaluated(WithOptParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), param_did: None }, [], Some(promoted[0])) }
         Retag(_9);                       // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
         _7 = &(*_9);                     // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
         Retag(_7);                       // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
diff --git a/src/test/mir-opt/match_false_edges/rustc.full_tested_match.PromoteTemps.after.mir b/src/test/mir-opt/match_false_edges/rustc.full_tested_match.PromoteTemps.after.mir
index 3e1dec697b76f..83aeceea1e6d2 100644
--- a/src/test/mir-opt/match_false_edges/rustc.full_tested_match.PromoteTemps.after.mir
+++ b/src/test/mir-opt/match_false_edges/rustc.full_tested_match.PromoteTemps.after.mir
@@ -76,10 +76,10 @@ fn full_tested_match() -> () {
         _11 = const full_tested_match::promoted[0]; // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15
                                          // ty::Const
                                          // + ty: &std::option::Option<i32>
-                                         // + val: Unevaluated(DefId(0:5 ~ match_false_edges[317d]::full_tested_match[0]), [], Some(promoted[0]))
+                                         // + val: Unevaluated(WithOptParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match[0]), param_did: None }, [], Some(promoted[0]))
                                          // mir::Constant
                                          // + span: $DIR/match_false_edges.rs:16:14: 16:15
-                                         // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(DefId(0:5 ~ match_false_edges[317d]::full_tested_match[0]), [], Some(promoted[0])) }
+                                         // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(WithOptParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match[0]), param_did: None }, [], Some(promoted[0])) }
         _6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15
         _4 = &shallow _2;                // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
         StorageLive(_7);                 // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27
diff --git a/src/test/mir-opt/retag/rustc.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag/rustc.main.SimplifyCfg-elaborate-drops.after.mir
index c8c5da37abe32..67df09f18b475 100644
--- a/src/test/mir-opt/retag/rustc.main.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/retag/rustc.main.SimplifyCfg-elaborate-drops.after.mir
@@ -184,10 +184,10 @@ fn main() -> () {
         _27 = const main::promoted[0];   // scope 7 at $DIR/retag.rs:47:21: 47:23
                                          // ty::Const
                                          // + ty: &i32
-                                         // + val: Unevaluated(DefId(0:13 ~ retag[317d]::main[0]), [], Some(promoted[0]))
+                                         // + val: Unevaluated(WithOptParam { did: DefId(0:13 ~ retag[317d]::main[0]), param_did: None }, [], Some(promoted[0]))
                                          // mir::Constant
                                          // + span: $DIR/retag.rs:47:21: 47:23
-                                         // + literal: Const { ty: &i32, val: Unevaluated(DefId(0:13 ~ retag[317d]::main[0]), [], Some(promoted[0])) }
+                                         // + literal: Const { ty: &i32, val: Unevaluated(WithOptParam { did: DefId(0:13 ~ retag[317d]::main[0]), param_did: None }, [], Some(promoted[0])) }
         Retag(_27);                      // scope 7 at $DIR/retag.rs:47:21: 47:23
         _23 = &(*_27);                   // scope 7 at $DIR/retag.rs:47:21: 47:23
         Retag(_23);                      // scope 7 at $DIR/retag.rs:47:21: 47:23
diff --git a/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs b/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs
new file mode 100644
index 0000000000000..c8db91b62b58c
--- /dev/null
+++ b/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs
@@ -0,0 +1,36 @@
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+pub struct Struct<const N: usize>(());
+
+impl<const N: usize> Struct<N> {
+    pub fn new() -> Self {
+        Struct(())
+    }
+
+    pub fn same_ty<const M: usize>(&self) -> (usize, usize) {
+        (N, M)
+    }
+
+    pub fn different_ty<const M: u8>(&self) -> (usize, u8) {
+        (N, M)
+    }
+
+    pub fn containing_ty<T, const M: u8>(&self) -> (usize, u8) {
+        (std::mem::size_of::<T>() +  N, M)
+    }
+
+    pub fn we_have_to_go_deeper<const M: usize>(&self) -> Struct<M> {
+        Struct(())
+    }
+}
+
+pub trait Foo {
+    fn foo<const M: usize>(&self) -> usize;
+}
+
+impl Foo for Struct<7> {
+    fn foo<const M: usize>(&self) -> usize {
+        M
+    }
+}
diff --git a/src/test/ui/const-generics/type-dependent/const-arg-in-const-arg.rs b/src/test/ui/const-generics/type-dependent/const-arg-in-const-arg.rs
new file mode 100644
index 0000000000000..ae50252facd25
--- /dev/null
+++ b/src/test/ui/const-generics/type-dependent/const-arg-in-const-arg.rs
@@ -0,0 +1,26 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+#![feature(const_fn)]
+
+struct Foo;
+
+impl Foo {
+    fn foo<const N: usize>(&self) -> usize {
+        let f = self;
+        f.bar::<{
+            let f = Foo;
+            f.bar::<7>()
+        }>() + N
+    }
+
+    const fn bar<const M: usize>(&self) -> usize {
+        M
+    }
+}
+
+fn main() {
+    let f = Foo;
+
+    assert_eq!(f.foo::<13>(), 20)
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-61936.rs b/src/test/ui/const-generics/type-dependent/issue-61936.rs
new file mode 100644
index 0000000000000..2dd6c0cd24191
--- /dev/null
+++ b/src/test/ui/const-generics/type-dependent/issue-61936.rs
@@ -0,0 +1,47 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+trait SliceExt<T: Clone> {
+    fn array_windows<'a, const N: usize>(&'a self) -> ArrayWindows<'a, T, N>;
+}
+
+impl <T: Clone> SliceExt<T> for [T] {
+   fn array_windows<'a, const N: usize>(&'a self) -> ArrayWindows<'a, T, N> {
+       ArrayWindows{ idx: 0, slice: &self }
+   }
+}
+
+struct ArrayWindows<'a, T, const N: usize> {
+    slice: &'a [T],
+    idx: usize,
+}
+
+impl <'a, T: Clone, const N: usize> Iterator for ArrayWindows<'a, T, N> {
+    type Item = [T; N];
+    fn next(&mut self) -> Option<Self::Item> {
+        let mut res = unsafe{ std::mem::zeroed() };
+        let mut ptr = &mut res as *mut [T; N] as *mut T;
+
+        for i in 0..N {
+            match self.slice[i..].get(i) {
+                None => return None,
+                Some(elem) => unsafe { std::ptr::write_volatile(ptr, elem.clone())},
+            };
+            ptr = ptr.wrapping_add(1);
+            self.idx += 1;
+        }
+
+        Some(res)
+    }
+}
+
+const FOUR: usize = 4;
+
+fn main() {
+    let v: Vec<usize> = vec![100; 0usize];
+
+    for array in v.as_slice().array_windows::<FOUR>() {
+        assert_eq!(array, [0, 0, 0, 0])
+    }
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-63695.rs b/src/test/ui/const-generics/type-dependent/issue-63695.rs
new file mode 100644
index 0000000000000..f3c2e1775940f
--- /dev/null
+++ b/src/test/ui/const-generics/type-dependent/issue-63695.rs
@@ -0,0 +1,17 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+trait T {
+    fn test<const A: i32>(&self) -> i32 { A }
+}
+
+struct S();
+
+impl T for S {}
+
+fn main() {
+    let foo = S();
+    assert_eq!(foo.test::<8i32>(), 8);
+    assert_eq!(foo.test::<16i32>(), 16);
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-69816.rs b/src/test/ui/const-generics/type-dependent/issue-69816.rs
new file mode 100644
index 0000000000000..cbe86cef3230f
--- /dev/null
+++ b/src/test/ui/const-generics/type-dependent/issue-69816.rs
@@ -0,0 +1,20 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+trait IterExt: Sized + Iterator {
+    fn default_for_size<const N: usize>(self) -> [Self::Item; N]
+    where
+        [Self::Item; N]: Default,
+    {
+        Default::default()
+    }
+}
+
+impl<T: Iterator> IterExt for T {}
+
+fn main(){
+    const N: usize = 10;
+    let arr = (0u32..10).default_for_size::<N>();
+    assert_eq!(arr, [0; 10]);
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-70507.rs b/src/test/ui/const-generics/type-dependent/issue-70507.rs
new file mode 100644
index 0000000000000..6fcf4116d437c
--- /dev/null
+++ b/src/test/ui/const-generics/type-dependent/issue-70507.rs
@@ -0,0 +1,47 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+trait ConstChunksExactTrait<T> {
+    fn const_chunks_exact<const N: usize>(&self) -> ConstChunksExact<'_, T, {N}>;
+}
+
+impl <T> ConstChunksExactTrait<T> for [T] {
+    fn const_chunks_exact<const N: usize>(&self) -> ConstChunksExact<'_, T, {N}> {
+        assert!(N != 0);
+        let rem = self.len() % N;
+        let len = self.len() - rem;
+        let (fst, _) = self.split_at(len);
+        ConstChunksExact { v: fst, }
+    }
+}
+
+struct ConstChunksExact<'a, T: 'a, const N: usize> {
+    v: &'a [T],
+}
+
+impl <'a, T: std::fmt::Debug, const N: usize> Iterator for ConstChunksExact<'a, T, {N}> {
+    type Item = &'a [T; N];
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.v.len() < N {
+            None
+        } else {
+            let (fst, snd) = self.v.split_at(N);
+
+            self.v = snd;
+            let ptr = fst.as_ptr() as *const _;
+            Some(unsafe { &*ptr})
+        }
+    }
+}
+
+fn main() {
+    let slice = &[1i32, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+
+    let mut iter = [[1, 2, 3], [4, 5, 6], [7, 8, 9]].iter();
+
+    for a in slice.const_chunks_exact::<3>() {
+        assert_eq!(a, iter.next().unwrap());
+    }
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-71382.rs b/src/test/ui/const-generics/type-dependent/issue-71382.rs
new file mode 100644
index 0000000000000..05abd488816ff
--- /dev/null
+++ b/src/test/ui/const-generics/type-dependent/issue-71382.rs
@@ -0,0 +1,24 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete
+
+struct Test;
+
+fn pass() -> u8 {
+    42
+}
+
+impl Test {
+    pub fn call_me(&self) -> u8 {
+        self.test::<pass>()
+    }
+
+    fn test<const FN: fn() -> u8>(&self) -> u8 {
+        //~^ ERROR using function pointers as const generic parameters is forbidden
+        FN()
+    }
+}
+
+fn main() {
+    let x = Test;
+    assert_eq!(x.call_me(), 42);
+}
diff --git a/src/test/ui/const-generics/type-dependent/issue-71382.stderr b/src/test/ui/const-generics/type-dependent/issue-71382.stderr
new file mode 100644
index 0000000000000..f441b71031ece
--- /dev/null
+++ b/src/test/ui/const-generics/type-dependent/issue-71382.stderr
@@ -0,0 +1,17 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-71382.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: using function pointers as const generic parameters is forbidden
+  --> $DIR/issue-71382.rs:15:23
+   |
+LL |     fn test<const FN: fn() -> u8>(&self) -> u8 {
+   |                       ^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/src/test/ui/const-generics/type-dependent/non-local.rs b/src/test/ui/const-generics/type-dependent/non-local.rs
new file mode 100644
index 0000000000000..e6f3eb075f1da
--- /dev/null
+++ b/src/test/ui/const-generics/type-dependent/non-local.rs
@@ -0,0 +1,24 @@
+// aux-build:type_dependent_lib.rs
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+extern crate type_dependent_lib;
+
+use type_dependent_lib::*;
+
+fn main() {
+    let s = Struct::<42>::new();
+    assert_eq!(s.same_ty::<7>(), (42, 7));
+    assert_eq!(s.different_ty::<19>(), (42, 19));
+    assert_eq!(Struct::<1337>::new().different_ty::<96>(), (1337, 96));
+    assert_eq!(
+        Struct::<18>::new()
+            .we_have_to_go_deeper::<19>()
+            .containing_ty::<Option<u32>, 3>(),
+        (27, 3),
+    );
+
+    let s = Struct::<7>::new();
+    assert_eq!(s.foo::<18>(), 18);
+}
diff --git a/src/test/ui/const-generics/type-dependent/qpath.rs b/src/test/ui/const-generics/type-dependent/qpath.rs
new file mode 100644
index 0000000000000..f3f98e5faf52d
--- /dev/null
+++ b/src/test/ui/const-generics/type-dependent/qpath.rs
@@ -0,0 +1,12 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct A;
+impl A {
+    fn foo<const N: usize>() -> usize { N + 1 }
+}
+
+fn main() {
+    assert_eq!(A::foo::<7>(), 8);
+}
diff --git a/src/test/ui/const-generics/type-dependent/simple.rs b/src/test/ui/const-generics/type-dependent/simple.rs
new file mode 100644
index 0000000000000..cc7c50d8fd835
--- /dev/null
+++ b/src/test/ui/const-generics/type-dependent/simple.rs
@@ -0,0 +1,12 @@
+// run-pass
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct R;
+
+impl R {
+    fn method<const N: u8>(&self) -> u8 { N }
+}
+fn main() {
+    assert_eq!(R.method::<1u8>(), 1);
+}
diff --git a/src/test/ui/const-generics/type-dependent/type-mismatch.rs b/src/test/ui/const-generics/type-dependent/type-mismatch.rs
new file mode 100644
index 0000000000000..0c71f338bd262
--- /dev/null
+++ b/src/test/ui/const-generics/type-dependent/type-mismatch.rs
@@ -0,0 +1,12 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete
+
+struct R;
+
+impl R {
+    fn method<const N: u8>(&self) -> u8 { N }
+}
+fn main() {
+    assert_eq!(R.method::<1u16>(), 1);
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/const-generics/type-dependent/type-mismatch.stderr b/src/test/ui/const-generics/type-dependent/type-mismatch.stderr
new file mode 100644
index 0000000000000..5bb7c5b0ea9bf
--- /dev/null
+++ b/src/test/ui/const-generics/type-dependent/type-mismatch.stderr
@@ -0,0 +1,23 @@
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/type-mismatch.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error[E0308]: mismatched types
+  --> $DIR/type-mismatch.rs:10:27
+   |
+LL |     assert_eq!(R.method::<1u16>(), 1);
+   |                           ^^^^ expected `u8`, found `u16`
+   |
+help: change the type of the numeric literal from `u16` to `u8`
+   |
+LL |     assert_eq!(R.method::<1u8>(), 1);
+   |                           ^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/unknown_adt.rs b/src/test/ui/const-generics/unknown_adt.rs
new file mode 100644
index 0000000000000..0ba9945b399ae
--- /dev/null
+++ b/src/test/ui/const-generics/unknown_adt.rs
@@ -0,0 +1,7 @@
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+fn main() {
+    let _: UnknownStruct<7>;
+    //~^ ERROR cannot find type `UnknownStruct`
+}
diff --git a/src/test/ui/const-generics/unknown_adt.stderr b/src/test/ui/const-generics/unknown_adt.stderr
new file mode 100644
index 0000000000000..b2e287b762c69
--- /dev/null
+++ b/src/test/ui/const-generics/unknown_adt.stderr
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `UnknownStruct` in this scope
+  --> $DIR/unknown_adt.rs:5:12
+   |
+LL |     let _: UnknownStruct<7>;
+   |            ^^^^^^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_lock.rs b/src/tools/clippy/clippy_lints/src/await_holding_lock.rs
index a88f922d8e03d..d37dbed1d5920 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_lock.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_lock.rs
@@ -59,7 +59,7 @@ impl LateLintPass<'_, '_> for AwaitHoldingLock {
                 hir_id: body.value.hir_id,
             };
             let def_id = cx.tcx.hir().body_owner_def_id(body_id);
-            let tables = cx.tcx.typeck_tables_of(def_id);
+            let tables = cx.tcx.typeck_tables_of(cx.tcx.with_opt_param(def_id));
             check_interior_types(cx, &tables.generator_interior_types, body.value.span);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/consts.rs b/src/tools/clippy/clippy_lints/src/consts.rs
index 22c5acca064e9..6e5ea04d035ed 100644
--- a/src/tools/clippy/clippy_lints/src/consts.rs
+++ b/src/tools/clippy/clippy_lints/src/consts.rs
@@ -332,7 +332,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
                 let result = self
                     .lcx
                     .tcx
-                    .const_eval_resolve(self.param_env, def_id, substs, None, None)
+                    .const_eval_resolve(self.param_env, self.lcx.tcx.with_opt_param(def_id), substs, None, None)
                     .ok()
                     .map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?;
                 let result = miri_to_const(&result);
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index 8d1e91f9adbd6..dd8e8557bb786 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -229,7 +229,7 @@ fn lint_for_missing_headers<'a, 'tcx>(
                 if let Some(body_id) = body_id;
                 if let Some(future) = cx.tcx.lang_items().future_trait();
                 let def_id = cx.tcx.hir().body_owner_def_id(body_id);
-                let mir = cx.tcx.optimized_mir(def_id.to_def_id());
+                let mir = cx.tcx.optimized_mir(cx.tcx.with_opt_param(def_id.to_def_id()));
                 let ret_ty = mir.return_ty();
                 if implements_trait(cx, ret_ty, future, &[]);
                 if let ty::Opaque(_, subs) = ret_ty.kind;
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 92812816461c5..0c2a9bcf337f7 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -124,7 +124,7 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it
                 let impl_item_def_id = cx.tcx.hir().local_def_id(impl_item.id.hir_id);
                 let mut fpu = FindPanicUnwrap {
                     lcx: cx,
-                    tables: cx.tcx.typeck_tables_of(impl_item_def_id),
+                    tables: cx.tcx.typeck_tables_of(cx.tcx.with_opt_param(impl_item_def_id)),
                     result: Vec::new(),
                 };
                 fpu.visit_expr(&body.value);
diff --git a/src/tools/clippy/clippy_lints/src/functions.rs b/src/tools/clippy/clippy_lints/src/functions.rs
index 1f9bd7a691b52..9ea0c31899528 100644
--- a/src/tools/clippy/clippy_lints/src/functions.rs
+++ b/src/tools/clippy/clippy_lints/src/functions.rs
@@ -497,7 +497,7 @@ fn is_mutable_pat(cx: &LateContext<'_, '_>, pat: &hir::Pat<'_>, tys: &mut FxHash
     if cx.tcx.has_typeck_tables(def_id) {
         is_mutable_ty(
             cx,
-            &cx.tcx.typeck_tables_of(def_id.expect_local()).pat_ty(pat),
+            &cx.tcx.typeck_tables_of(cx.tcx.with_opt_param(def_id.expect_local())).pat_ty(pat),
             pat.span,
             tys,
         )
@@ -617,7 +617,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
                     if self.cx.tcx.has_typeck_tables(def_id)
                         && is_mutable_ty(
                             self.cx,
-                            self.cx.tcx.typeck_tables_of(def_id.expect_local()).expr_ty(arg),
+                            self.cx.tcx.typeck_tables_of(self.cx.tcx.with_opt_param(def_id.expect_local())).expr_ty(arg),
                             arg.span,
                             &mut tys,
                         )
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index c4308fd26a302..bd54c90024850 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -139,7 +139,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitReturn {
             return;
         }
 
-        let mir = cx.tcx.optimized_mir(def_id.to_def_id());
+        let mir = cx.tcx.optimized_mir(cx.tcx.with_opt_param(def_id.to_def_id()));
 
         // checking return type through MIR, HIR is not able to determine inferred closure return types
         // make sure it's not a macro
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index 9cfc8d1913497..2470afc70e5e2 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -116,7 +116,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingConstForFn {
             FnKind::Closure(..) => return,
         }
 
-        let mir = cx.tcx.optimized_mir(def_id);
+        let mir = cx.tcx.optimized_mir(cx.tcx.with_opt_param(def_id.to_def_id()));
 
         if let Err((span, err)) = is_min_const_fn(cx.tcx, def_id.to_def_id(), &mir) {
             if rustc_mir::const_eval::is_min_const_fn(cx.tcx, def_id.to_def_id()) {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index d563eb886ae7e..4a7396e736989 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -84,7 +84,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantClone {
             return;
         }
 
-        let mir = cx.tcx.optimized_mir(def_id.to_def_id());
+        let mir = cx.tcx.optimized_mir(cx.tcx.with_opt_param(def_id.to_def_id()));
 
         let maybe_storage_live_result = MaybeStorageLive
             .into_engine(cx.tcx, mir, def_id.to_def_id())
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 6d4c6c6ce1cea..da4f41dfeab9b 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -291,7 +291,7 @@ pub fn qpath_res(cx: &LateContext<'_, '_>, qpath: &hir::QPath<'_>, id: hir::HirI
         hir::QPath::TypeRelative(..) => {
             if cx.tcx.has_typeck_tables(id.owner.to_def_id()) {
                 cx.tcx
-                    .typeck_tables_of(id.owner.to_def_id().expect_local())
+                    .typeck_tables_of(cx.tcx.with_opt_param(id.owner))
                     .qpath_res(qpath, id)
             } else {
                 Res::Err