about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-07-06 08:10:42 +0000
committerbors <bors@rust-lang.org>2023-07-06 08:10:42 +0000
commit4dd1719b3406d80f539d2f49e9842f3563908632 (patch)
tree325d27bb8fdf63ef0f748a9d8a029326d8e4799b
parentb112bc5529cfa8d8a9000f7a85278ece3232e579 (diff)
parentdeda49e7b7df44631720fa94f27a3a430772cd77 (diff)
downloadrust-4dd1719b3406d80f539d2f49e9842f3563908632.tar.gz
rust-4dd1719b3406d80f539d2f49e9842f3563908632.zip
Auto merge of #113377 - BoxyUwU:move_ty_ctors_to_ty, r=compiler-errors
Move `TyCtxt::mk_x` to `Ty::new_x` where applicable

Part of rust-lang/compiler-team#616

turns out there's a lot of places we construct `Ty` this is a ridiculously huge PR :S

r? `@oli-obk`
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs10
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs13
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/codegen_i128.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/num.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs10
-rw-r--r--compiler/rustc_codegen_gcc/src/type_of.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs11
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/utils.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs36
-rw-r--r--compiler/rustc_codegen_llvm/src/type_of.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/va_arg.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs14
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs9
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs5
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs4
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/bounds.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs74
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/object_safety.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/autoderef.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs172
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs56
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs32
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs17
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs35
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs88
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs46
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs17
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs58
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs15
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs5
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs4
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs2
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs6
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs4
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs6
-rw-r--r--compiler/rustc_infer/src/infer/generalize.rs2
-rw-r--r--compiler/rustc_infer/src/infer/higher_ranked/mod.rs10
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs35
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs2
-rw-r--r--compiler/rustc_infer/src/traits/util.rs4
-rw-r--r--compiler/rustc_lint/src/builtin.rs6
-rw-r--r--compiler/rustc_lint/src/context.rs2
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs5
-rw-r--r--compiler/rustc_lint/src/types.rs8
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs3
-rw-r--r--compiler/rustc_middle/src/infer/unify_key.rs6
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs2
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs24
-rw-r--r--compiler/rustc_middle/src/ty/_match.rs2
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs2
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs4
-rw-r--r--compiler/rustc_middle/src/ty/context.rs396
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs2
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs10
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs4
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs6
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs41
-rw-r--r--compiler/rustc_middle/src/ty/opaque_types.rs8
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs37
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs398
-rw-r--r--compiler/rustc_middle/src/ty/util.rs22
-rw-r--r--compiler/rustc_middle/src/values.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs10
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs18
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs13
-rw-r--r--compiler/rustc_mir_transform/src/check_alignment.rs2
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_box_derefs.rs2
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs24
-rw-r--r--compiler/rustc_mir_transform/src/large_enums.rs16
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs23
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs81
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs6
-rw-r--r--compiler/rustc_trait_selection/src/solve/canonicalize.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs29
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs32
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs2
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs17
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs5
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs4
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs4
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs2
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs2
-rw-r--r--src/tools/miri/src/eval.rs9
-rw-r--r--src/tools/miri/src/machine.rs6
-rw-r--r--src/tools/miri/src/shims/backtrace.rs4
-rw-r--r--src/tools/miri/src/shims/env.rs3
-rw-r--r--src/tools/miri/src/shims/os_str.rs5
165 files changed, 1388 insertions, 1187 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 42e50fd0fad..d292611e6a2 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -1050,7 +1050,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             Some(def_id) => type_known_to_meet_bound_modulo_regions(
                                 &self.infcx,
                                 self.param_env,
-                                tcx.mk_imm_ref(tcx.lifetimes.re_erased, ty),
+                                Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty),
                                 def_id,
                             ),
                             _ => false,
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 8ec872e2057..617c85174cb 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -508,7 +508,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         let generic_arg = substs[param_index as usize];
                         let identity_substs =
                             InternalSubsts::identity_for_item(self.infcx.tcx, adt.did());
-                        let base_ty = self.infcx.tcx.mk_adt(*adt, identity_substs);
+                        let base_ty = Ty::new_adt(self.infcx.tcx, *adt, identity_substs);
                         let base_generic_arg = identity_substs[param_index as usize];
                         let adt_desc = adt.descr();
 
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 2a0cb49672b..e45d3a2c882 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -1139,7 +1139,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                             _ => arg.fold_with(self),
                         }
                     });
-                tcx.mk_opaque(def_id, tcx.mk_substs_from_iter(substs))
+                Ty::new_opaque(tcx, def_id, tcx.mk_substs_from_iter(substs))
             }
         }
 
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 4a872eb251c..1a227f2d110 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -158,7 +158,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                         )
                         .emit()
                     });
-                    prev.ty = infcx.tcx.ty_error(guar);
+                    prev.ty = Ty::new_error(infcx.tcx, guar);
                 }
                 // Pick a better span if there is one.
                 // FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
@@ -248,13 +248,13 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
         instantiated_ty: OpaqueHiddenType<'tcx>,
     ) -> Ty<'tcx> {
         if let Some(e) = self.tainted_by_errors() {
-            return self.tcx.ty_error(e);
+            return Ty::new_error(self.tcx, e);
         }
 
         if let Err(guar) =
             check_opaque_type_parameter_valid(self.tcx, opaque_type_key, instantiated_ty.span)
         {
-            return self.tcx.ty_error(guar);
+            return Ty::new_error(self.tcx, guar);
         }
 
         let definition_ty = instantiated_ty
@@ -271,7 +271,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
             definition_ty,
         ) {
             Ok(hidden_ty) => hidden_ty,
-            Err(guar) => self.tcx.ty_error(guar),
+            Err(guar) => Ty::new_error(self.tcx, guar),
         }
     }
 }
@@ -313,7 +313,7 @@ fn check_opaque_type_well_formed<'tcx>(
 
     // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
     // the bounds that the function supplies.
-    let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), identity_substs);
+    let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), identity_substs);
     ocx.eq(&ObligationCause::misc(definition_span, def_id), param_env, opaque_ty, definition_ty)
         .map_err(|err| {
             infcx
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index c8ec1257d37..f22851d76b3 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -245,7 +245,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
                 .and(type_op::normalize::Normalize::new(ty))
                 .fully_perform(self.infcx, span)
                 .unwrap_or_else(|guar| TypeOpOutput {
-                    output: self.infcx.tcx.ty_error(guar),
+                    output: Ty::new_error(self.infcx.tcx, guar),
                     constraints: None,
                     error_info: None,
                 });
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 23c3b7b7016..7ed7e125b3c 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -237,7 +237,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
                     decl.hidden_type.span,
                     format!("could not resolve {:#?}", hidden_type.ty.kind()),
                 );
-                hidden_type.ty = infcx.tcx.ty_error(reported);
+                hidden_type.ty = Ty::new_error(infcx.tcx, reported);
             }
 
             (opaque_type_key, hidden_type)
@@ -520,7 +520,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
         for elem in place.projection.iter() {
             if place_ty.variant_index.is_none() {
                 if let Err(guar) = place_ty.ty.error_reported() {
-                    return PlaceTy::from_ty(self.tcx().ty_error(guar));
+                    return PlaceTy::from_ty(Ty::new_error(self.tcx(), guar));
                 }
             }
             place_ty = self.sanitize_projection(place_ty, elem, place, location, context);
@@ -656,7 +656,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                 PlaceTy::from_ty(match base_ty.kind() {
                     ty::Array(inner, _) => {
                         assert!(!from_end, "array subslices should not use from_end");
-                        tcx.mk_array(*inner, to - from)
+                        Ty::new_array(tcx, *inner, to - from)
                     }
                     ty::Slice(..) => {
                         assert!(from_end, "slice subslices should use from_end");
@@ -749,7 +749,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
     }
 
     fn error(&mut self) -> Ty<'tcx> {
-        self.tcx().ty_error_misc()
+        Ty::new_misc_error(self.tcx())
     }
 
     fn get_ambient_variance(&self, context: PlaceContext) -> ty::Variance {
@@ -1918,7 +1918,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         // and hence may contain unnormalized results.
                         let fn_sig = self.normalize(fn_sig, location);
 
-                        let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig);
+                        let ty_fn_ptr_from = Ty::new_fn_ptr(tcx, fn_sig);
 
                         if let Err(terr) = self.eq_types(
                             *ty,
@@ -1942,7 +1942,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             ty::Closure(_, substs) => substs.as_closure().sig(),
                             _ => bug!(),
                         };
-                        let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety));
+                        let ty_fn_ptr_from =
+                            Ty::new_fn_ptr(tcx, tcx.signature_unclosure(sig, *unsafety));
 
                         if let Err(terr) = self.eq_types(
                             *ty,
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index c871703429a..7821b82bf2b 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -685,7 +685,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                 assert_eq!(self.mir_def.to_def_id(), 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);
+                let generator_ty = Ty::new_generator(tcx, def_id, substs, movability);
                 let inputs_and_output =
                     self.infcx.tcx.mk_type_list(&[generator_ty, resume_ty, output]);
                 ty::Binder::dummy(inputs_and_output)
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 84e09cf0abe..199fa6861cf 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -665,7 +665,8 @@ pub(crate) fn codegen_drop<'tcx>(
 
                 let arg_value = drop_place.place_ref(
                     fx,
-                    fx.layout_of(fx.tcx.mk_ref(
+                    fx.layout_of(Ty::new_ref(
+                        fx.tcx,
                         fx.tcx.lifetimes.re_erased,
                         TypeAndMut { ty, mutbl: crate::rustc_hir::Mutability::Mut },
                     )),
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 5f78cce50e6..826ce60ed13 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -746,7 +746,7 @@ fn codegen_stmt<'tcx>(
                 }
                 Rvalue::ShallowInitBox(ref operand, content_ty) => {
                     let content_ty = fx.monomorphize(content_ty);
-                    let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty));
+                    let box_layout = fx.layout_of(Ty::new_box(fx.tcx, content_ty));
                     let operand = codegen_operand(fx, operand);
                     let operand = operand.load_scalar(fx);
                     lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
@@ -887,7 +887,7 @@ pub(crate) fn codegen_place<'tcx>(
                         let ptr = cplace.to_ptr();
                         cplace = CPlace::for_ptr(
                             ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * (from as i64)),
-                            fx.layout_of(fx.tcx.mk_array(*elem_ty, to - from)),
+                            fx.layout_of(Ty::new_array(fx.tcx, *elem_ty, to - from)),
                         );
                     }
                     ty::Slice(elem_ty) => {
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index 13568b198db..b2bc289a5b6 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -92,7 +92,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
     match bin_op {
         BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => unreachable!(),
         BinOp::Mul if is_signed => {
-            let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]);
+            let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]);
             let oflow = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32));
             let lhs = lhs.load_scalar(fx);
             let rhs = rhs.load_scalar(fx);
@@ -112,7 +112,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
             Some(CValue::by_val_pair(res, oflow, fx.layout_of(out_ty)))
         }
         BinOp::Add | BinOp::Sub | BinOp::Mul => {
-            let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]);
+            let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]);
             let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
             let param_types = vec![
                 AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index a694bb26afb..67ea20112fe 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -99,7 +99,7 @@ fn clif_pair_type_from_ty<'tcx>(
 
 /// Is a pointer to this type a fat ptr?
 pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
-    let ptr_ty = tcx.mk_ptr(TypeAndMut { ty, mutbl: rustc_hir::Mutability::Not });
+    let ptr_ty = Ty::new_ptr(tcx, TypeAndMut { ty, mutbl: rustc_hir::Mutability::Not });
     match &tcx.layout_of(ParamEnv::reveal_all().and(ptr_ty)).unwrap().abi {
         Abi::Scalar(_) => false,
         Abi::ScalarPair(_, _) => true,
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index bbd5f4be783..24ad0083a22 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -386,7 +386,7 @@ fn llvm_add_sub<'tcx>(
     // carry0 | carry1 -> carry or borrow respectively
     let cb_out = fx.bcx.ins().bor(cb0, cb1);
 
-    let layout = fx.layout_of(fx.tcx.mk_tup(&[fx.tcx.types.u8, fx.tcx.types.u64]));
+    let layout = fx.layout_of(Ty::new_tup(fx.tcx, &[fx.tcx.types.u8, fx.tcx.types.u64]));
     let val = CValue::by_val_pair(cb_out, c, layout);
     ret.write_cvalue(fx, val);
 }
diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs
index ac1a6cce096..8992f40fb90 100644
--- a/compiler/rustc_codegen_cranelift/src/num.rs
+++ b/compiler/rustc_codegen_cranelift/src/num.rs
@@ -270,7 +270,7 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
         _ => bug!("binop {:?} on checked int/uint lhs: {:?} rhs: {:?}", bin_op, in_lhs, in_rhs),
     };
 
-    let out_layout = fx.layout_of(fx.tcx.mk_tup(&[in_lhs.layout().ty, fx.tcx.types.bool]));
+    let out_layout = fx.layout_of(Ty::new_tup(fx.tcx, &[in_lhs.layout().ty, fx.tcx.types.bool]));
     CValue::by_val_pair(res, has_overflow, out_layout)
 }
 
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index a31fee39918..0b208be4e62 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -1147,19 +1147,19 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, codegen: &mut
 
     // Define the type up front for the signature of the rust_try function.
     let tcx = cx.tcx;
-    let i8p = tcx.mk_mut_ptr(tcx.types.i8);
+    let i8p = Ty::new_mut_ptr(tcx,tcx.types.i8);
     // `unsafe fn(*mut i8) -> ()`
-    let try_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig(
+    let try_fn_ty = Ty::new_fn_ptr(tcx,ty::Binder::dummy(tcx.mk_fn_sig(
         iter::once(i8p),
-        tcx.mk_unit(),
+        Ty::new_unit(tcx,),
         false,
         rustc_hir::Unsafety::Unsafe,
         Abi::Rust,
     )));
     // `unsafe fn(*mut i8, *mut i8) -> ()`
-    let catch_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig(
+    let catch_fn_ty = Ty::new_fn_ptr(tcx,ty::Binder::dummy(tcx.mk_fn_sig(
         [i8p, i8p].iter().cloned(),
-        tcx.mk_unit(),
+        Ty::new_unit(tcx,),
         false,
         rustc_hir::Unsafety::Unsafe,
         Abi::Rust,
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
index 74f016cf90a..e0823888f67 100644
--- a/compiler/rustc_codegen_gcc/src/type_of.rs
+++ b/compiler/rustc_codegen_gcc/src/type_of.rs
@@ -283,7 +283,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
             // only wide pointer boxes are handled as pointers
             // thin pointer boxes with scalar allocators are handled by the general logic below
             ty::Adt(def, substs) if def.is_box() && cx.layout_of(substs.type_at(1)).is_zst() => {
-                let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty());
+                let ptr_ty = Ty::new_mut_ptr(cx.tcx,self.ty.boxed_ty());
                 return cx.layout_of(ptr_ty).scalar_pair_element_gcc_type(cx, index, immediate);
             }
             _ => {}
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 28be6d033f8..d221bad28ef 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -351,7 +351,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     continue;
                 }
                 PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
-                    let ptr_ty = cx.tcx.mk_mut_ptr(arg.layout.ty);
+                    let ptr_ty = Ty::new_mut_ptr(cx.tcx, arg.layout.ty);
                     let ptr_layout = cx.layout_of(ptr_ty);
                     llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 0, true));
                     llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true));
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 839a7f333ba..42fdbd78618 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -24,6 +24,7 @@ use rustc_middle::ty;
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::Instance;
+use rustc_middle::ty::Ty;
 
 use std::cell::RefCell;
 use std::ffi::CString;
@@ -262,8 +263,8 @@ fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: DefId) -> Instance<
         tcx.symbol_name(instance).name,
         cx.fn_abi_of_fn_ptr(
             ty::Binder::dummy(tcx.mk_fn_sig(
-                [tcx.mk_unit()],
-                tcx.mk_unit(),
+                [Ty::new_unit(tcx)],
+                Ty::new_unit(tcx),
                 false,
                 hir::Unsafety::Unsafe,
                 Abi::Rust,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index ad07d637106..d61400d3fa3 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -168,7 +168,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
     // a (fat) pointer. Make sure it is not called for e.g. `Box<T, NonZSTAllocator>`.
     debug_assert_eq!(
         cx.size_and_align_of(ptr_type),
-        cx.size_and_align_of(cx.tcx.mk_mut_ptr(pointee_type))
+        cx.size_and_align_of(Ty::new_mut_ptr(cx.tcx, pointee_type))
     );
 
     let pointee_type_di_node = type_di_node(cx, pointee_type);
@@ -223,8 +223,11 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                     //        at all and instead emit regular struct debuginfo for it. We just
                     //        need to make sure that we don't break existing debuginfo consumers
                     //        by doing that (at least not without a warning period).
-                    let layout_type =
-                        if ptr_type.is_box() { cx.tcx.mk_mut_ptr(pointee_type) } else { ptr_type };
+                    let layout_type = if ptr_type.is_box() {
+                        Ty::new_mut_ptr(cx.tcx, pointee_type)
+                    } else {
+                        ptr_type
+                    };
 
                     let layout = cx.layout_of(layout_type);
                     let addr_field = layout.field(cx, abi::FAT_PTR_ADDR);
@@ -1298,7 +1301,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
 
     // All function pointers are described as opaque pointers. This could be improved in the future
     // by describing them as actual function pointers.
-    let void_pointer_ty = tcx.mk_imm_ptr(tcx.types.unit);
+    let void_pointer_ty = Ty::new_imm_ptr(tcx, tcx.types.unit);
     let void_pointer_type_di_node = type_di_node(cx, void_pointer_ty);
     let usize_di_node = type_di_node(cx, tcx.types.usize);
     let (pointer_size, pointer_align) = cx.size_and_align_of(void_pointer_ty);
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 0858f6b5f8e..b924c771af7 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -454,7 +454,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                         ty::Array(ct, _)
                             if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() =>
                         {
-                            cx.tcx.mk_imm_ptr(*ct)
+                            Ty::new_imm_ptr(cx.tcx, *ct)
                         }
                         _ => t,
                     };
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
index 6bcd3e5bf58..7be83638676 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
@@ -82,8 +82,8 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
         ty::Foreign(_) => {
             // Assert that pointers to foreign types really are thin:
             debug_assert_eq!(
-                cx.size_of(cx.tcx.mk_imm_ptr(pointee_tail_ty)),
-                cx.size_of(cx.tcx.mk_imm_ptr(cx.tcx.types.u8))
+                cx.size_of(Ty::new_imm_ptr(cx.tcx, pointee_tail_ty)),
+                cx.size_of(Ty::new_imm_ptr(cx.tcx, cx.tcx.types.u8))
             );
             None
         }
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 31bafa87814..a254c86c291 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -873,23 +873,29 @@ fn get_rust_try_fn<'ll, 'tcx>(
 
     // Define the type up front for the signature of the rust_try function.
     let tcx = cx.tcx;
-    let i8p = tcx.mk_mut_ptr(tcx.types.i8);
+    let i8p = Ty::new_mut_ptr(tcx, tcx.types.i8);
     // `unsafe fn(*mut i8) -> ()`
-    let try_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig(
-        [i8p],
-        tcx.mk_unit(),
-        false,
-        hir::Unsafety::Unsafe,
-        Abi::Rust,
-    )));
+    let try_fn_ty = Ty::new_fn_ptr(
+        tcx,
+        ty::Binder::dummy(tcx.mk_fn_sig(
+            [i8p],
+            Ty::new_unit(tcx),
+            false,
+            hir::Unsafety::Unsafe,
+            Abi::Rust,
+        )),
+    );
     // `unsafe fn(*mut i8, *mut i8) -> ()`
-    let catch_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig(
-        [i8p, i8p],
-        tcx.mk_unit(),
-        false,
-        hir::Unsafety::Unsafe,
-        Abi::Rust,
-    )));
+    let catch_fn_ty = Ty::new_fn_ptr(
+        tcx,
+        ty::Binder::dummy(tcx.mk_fn_sig(
+            [i8p, i8p],
+            Ty::new_unit(tcx),
+            false,
+            hir::Unsafety::Unsafe,
+            Abi::Rust,
+        )),
+    );
     // `unsafe fn(unsafe fn(*mut i8) -> (), *mut i8, unsafe fn(*mut i8, *mut i8) -> ()) -> i32`
     let rust_fn_sig = ty::Binder::dummy(cx.tcx.mk_fn_sig(
         [try_fn_ty, i8p, catch_fn_ty],
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 3339e4e07ed..58e97be34f2 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -337,12 +337,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
             // only wide pointer boxes are handled as pointers
             // thin pointer boxes with scalar allocators are handled by the general logic below
             ty::Adt(def, substs) if def.is_box() && cx.layout_of(substs.type_at(1)).is_zst() => {
-                let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty());
+                let ptr_ty = Ty::new_mut_ptr(cx.tcx, self.ty.boxed_ty());
                 return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate);
             }
             // `dyn* Trait` has the same ABI as `*mut dyn Trait`
             ty::Dynamic(bounds, region, ty::DynStar) => {
-                let ptr_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_dynamic(bounds, region, ty::Dyn));
+                let ptr_ty =
+                    Ty::new_mut_ptr(cx.tcx, Ty::new_dynamic(cx.tcx, bounds, region, ty::Dyn));
                 return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate);
             }
             _ => {}
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index b19398e68c2..8800caa71d6 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -73,7 +73,7 @@ fn emit_ptr_va_arg<'ll, 'tcx>(
     let layout = bx.cx.layout_of(target_ty);
     let (llty, size, align) = if indirect {
         (
-            bx.cx.layout_of(bx.cx.tcx.mk_imm_ptr(target_ty)).llvm_type(bx.cx),
+            bx.cx.layout_of(Ty::new_imm_ptr(bx.cx.tcx, target_ty)).llvm_type(bx.cx),
             bx.cx.data_layout().pointer_size,
             bx.cx.data_layout().pointer_align,
         )
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index f8ced6949d5..9133601ecd1 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -199,7 +199,7 @@ fn vtable_ptr_ty<'tcx, Cx: CodegenMethods<'tcx>>(
     cx.scalar_pair_element_backend_type(
         cx.layout_of(match kind {
             // vtable is the second field of `*mut dyn Trait`
-            ty::Dyn => cx.tcx().mk_mut_ptr(target),
+            ty::Dyn => Ty::new_mut_ptr(cx.tcx(), target),
             // vtable is the second field of `dyn* Trait`
             ty::DynStar => target,
         }),
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 93bed3a4a4a..9d1b3ce8266 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1505,9 +1505,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         if let Some(slot) = self.personality_slot {
             slot
         } else {
-            let layout = cx.layout_of(
-                cx.tcx().mk_tup(&[cx.tcx().mk_mut_ptr(cx.tcx().types.u8), cx.tcx().types.i32]),
-            );
+            let layout = cx.layout_of(Ty::new_tup(
+                cx.tcx(),
+                &[Ty::new_mut_ptr(cx.tcx(), cx.tcx().types.u8), cx.tcx().types.i32],
+            ));
             let slot = PlaceRef::alloca(bx, layout);
             self.personality_slot = Some(slot);
             slot
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index c6589a40392..1ee89b3d5e8 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -5,6 +5,7 @@ use rustc_middle::mir;
 use rustc_middle::ty;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
+use rustc_middle::ty::Ty;
 use rustc_session::config::DebugInfo;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{BytePos, Span};
@@ -421,9 +422,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         let create_alloca = |bx: &mut Bx, place: PlaceRef<'tcx, Bx::Value>, refcount| {
             // Create a variable which will be a pointer to the actual value
-            let ptr_ty = bx
-                .tcx()
-                .mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: place.layout.ty });
+            let ptr_ty = Ty::new_ptr(
+                bx.tcx(),
+                ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: place.layout.ty },
+            );
             let ptr_layout = bx.layout_of(ptr_ty);
             let alloca = PlaceRef::alloca(bx, ptr_layout);
             bx.set_var_name(alloca.llval, &format!("{}.ref{}.dbg.spill", var.name, refcount));
@@ -525,8 +527,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 };
 
                 for _ in 0..var.references {
-                    var_ty =
-                        bx.tcx().mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: var_ty });
+                    var_ty = Ty::new_ptr(
+                        bx.tcx(),
+                        ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: var_ty },
+                    );
                 }
 
                 self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index a58a61cd567..ab493ae5c1f 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -61,7 +61,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         layout: TyAndLayout<'tcx>,
     ) -> Self {
         assert!(layout.is_unsized(), "tried to allocate indirect place for sized values");
-        let ptr_ty = bx.cx().tcx().mk_mut_ptr(layout.ty);
+        let ptr_ty = Ty::new_mut_ptr(bx.cx().tcx(), layout.ty);
         let ptr_layout = bx.cx().layout_of(ptr_ty);
         Self::alloca(bx, ptr_layout)
     }
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 2d3d0ec68b8..ab9eb421c5a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -581,7 +581,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
             mir::Rvalue::Ref(_, bk, place) => {
                 let mk_ref = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
-                    tcx.mk_ref(
+                    Ty::new_ref(
+                        tcx,
                         tcx.lifetimes.re_erased,
                         ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() },
                     )
@@ -592,7 +593,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             mir::Rvalue::CopyForDeref(place) => self.codegen_operand(bx, &Operand::Copy(place)),
             mir::Rvalue::AddressOf(mutability, place) => {
                 let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
-                    tcx.mk_ptr(ty::TypeAndMut { ty, mutbl: mutability })
+                    Ty::new_ptr(tcx, ty::TypeAndMut { ty, mutbl: mutability })
                 };
                 self.codegen_place_to_pointer(bx, place, mk_ptr)
             }
@@ -644,7 +645,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     lhs.layout.ty,
                 );
                 let val_ty = op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty);
-                let operand_ty = bx.tcx().mk_tup(&[val_ty, bx.tcx().types.bool]);
+                let operand_ty = Ty::new_tup(bx.tcx(), &[val_ty, bx.tcx().types.bool]);
                 OperandRef { val: result, layout: bx.cx().layout_of(operand_ty) }
             }
 
@@ -734,7 +735,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let lloperand = operand.immediate();
 
                 let content_ty = self.monomorphize(content_ty);
-                let box_layout = bx.cx().layout_of(bx.tcx().mk_box(content_ty));
+                let box_layout = bx.cx().layout_of(Ty::new_box(bx.tcx(), content_ty));
                 let llty_ptr = bx.cx().backend_type(box_layout);
 
                 let val = bx.pointercast(lloperand, llty_ptr);
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 4f10e4837ce..ed64a7655b5 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -170,7 +170,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     sym::pref_align_of | sym::variant_count => self.tcx.types.usize,
                     sym::needs_drop => self.tcx.types.bool,
                     sym::type_id => self.tcx.types.u128,
-                    sym::type_name => self.tcx.mk_static_str(),
+                    sym::type_name => Ty::new_static_str(self.tcx.tcx),
                     _ => bug!(),
                 };
                 let val = self.ctfe_query(None, |tcx| {
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index 7bca7efdf5a..e04764636cc 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -22,7 +22,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     ) -> InterpResult<'tcx> {
         let (val, overflowed, ty) = self.overflowing_binary_op(op, &left, &right)?;
         debug_assert_eq!(
-            self.tcx.mk_tup(&[ty, self.tcx.types.bool]),
+            Ty::new_tup(self.tcx.tcx, &[ty, self.tcx.types.bool]),
             dest.layout.ty,
             "type mismatch for result of {:?}",
             op,
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 2a31a59ad6c..24c1fe43d0c 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -9,6 +9,7 @@ use rustc_index::IndexSlice;
 use rustc_middle::mir;
 use rustc_middle::ty;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_middle::ty::Ty;
 use rustc_target::abi::{self, Abi, Align, FieldIdx, HasDataLayout, Size, FIRST_VARIANT};
 
 use super::{
@@ -395,7 +396,7 @@ where
         // (Transmuting is okay since this is an in-memory place. We also double-check the size
         // stays the same.)
         let (len, e_ty) = mplace.layout.ty.simd_size_and_type(*self.tcx);
-        let array = self.tcx.mk_array(e_ty, len);
+        let array = Ty::new_array(self.tcx.tcx, e_ty, len);
         let layout = self.layout_of(array)?;
         assert_eq!(layout.size, mplace.layout.size);
         Ok((MPlaceTy { layout, ..*mplace }, len))
@@ -775,7 +776,8 @@ where
         let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self);
         let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) };
 
-        let ty = self.tcx.mk_ref(
+        let ty = Ty::new_ref(
+            self.tcx.tcx,
             self.tcx.lifetimes.re_static,
             ty::TypeAndMut { ty: self.tcx.types.str_, mutbl },
         );
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index 91da930db4f..d7d31fe1887 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -12,6 +12,7 @@ use either::{Left, Right};
 use rustc_middle::mir;
 use rustc_middle::ty;
 use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::Ty;
 use rustc_target::abi::{self, Abi, VariantIdx};
 
 use super::{
@@ -317,7 +318,9 @@ where
         let (meta, ty) = match base.layout.ty.kind() {
             // It is not nice to match on the type, but that seems to be the only way to
             // implement this.
-            ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(*inner, inner_len)),
+            ty::Array(inner, _) => {
+                (MemPlaceMeta::None, Ty::new_array(self.tcx.tcx, *inner, inner_len))
+            }
             ty::Slice(..) => {
                 let len = Scalar::from_target_usize(inner_len, self);
                 (MemPlaceMeta::Meta(len), base.layout.ty)
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 719d8a14b41..15823a5975e 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -650,7 +650,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // Adjust receiver argument. Layout can be any (thin) ptr.
                 args[0] = ImmTy::from_immediate(
                     Scalar::from_maybe_pointer(adjusted_receiver, self).into(),
-                    self.layout_of(self.tcx.mk_mut_ptr(dyn_ty))?,
+                    self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, dyn_ty))?,
                 )
                 .into();
                 trace!("Patched receiver operand to {:#?}", args[0]);
@@ -703,7 +703,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         let arg = ImmTy::from_immediate(
             place.to_ref(self),
-            self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?,
+            self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, place.layout.ty))?,
         );
         let ret = MPlaceTy::fake_alloc_zst(self.layout_of(self.tcx.types.unit)?);
 
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 36c76e53231..015a4aa94cd 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -223,7 +223,7 @@ impl Qualif for CustomEq {
         def: AdtDef<'tcx>,
         substs: SubstsRef<'tcx>,
     ) -> bool {
-        let ty = cx.tcx.mk_adt(def, substs);
+        let ty = Ty::new_adt(cx.tcx, def, substs);
         !ty.is_structural_eq_shallow(cx.tcx)
     }
 }
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index dd80f745c2f..1b39a76e460 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -17,7 +17,7 @@ use rustc_middle::mir;
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::{self, List, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, List, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::Span;
 
 use rustc_index::{Idx, IndexSlice, IndexVec};
@@ -867,7 +867,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
             let ty = local_decls[place.local].ty;
             let span = statement.source_info.span;
 
-            let ref_ty = tcx.mk_ref(
+            let ref_ty = Ty::new_ref(
+                tcx,
                 tcx.lifetimes.re_erased,
                 ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
             );
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index a6ee7215617..b13de770137 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -363,7 +363,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                                 );
                                 emitted_bad_param_err = true;
                             }
-                            tcx.mk_bound(
+                            Ty::new_bound(
+                                tcx,
                                 ty::INNERMOST,
                                 ty::BoundTy {
                                     var: ty::BoundVar::from_usize(num_bound_vars),
@@ -527,7 +528,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                         }
                         let reported = err.emit();
                         term = match def_kind {
-                            hir::def::DefKind::AssocTy => tcx.ty_error(reported).into(),
+                            hir::def::DefKind::AssocTy => Ty::new_error(tcx, reported).into(),
                             hir::def::DefKind::AssocConst => ty::Const::new_error(
                                 tcx,
                                 reported,
@@ -558,7 +559,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                 // type bound into a trait predicate, since we only want to add predicates
                 // for the `Self` type.
                 if !only_self_bounds.0 {
-                    let param_ty = tcx.mk_alias(ty::Projection, projection_ty.skip_binder());
+                    let param_ty = Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder());
                     self.add_bounds(
                         param_ty,
                         ast_bounds.iter(),
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index dc17ef7048d..ddf99853b2e 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -357,7 +357,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     let projection_ty = pred.skip_binder().projection_ty;
 
                     let substs_with_infer_self = tcx.mk_substs_from_iter(
-                        std::iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
+                        std::iter::once(Ty::new_var(tcx, ty::TyVid::from_u32(0)).into())
                             .chain(projection_ty.substs.iter().skip(1)),
                     );
 
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index a6503e032c7..3d698462840 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -443,7 +443,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     }
                     if let (hir::TyKind::Infer, false) = (&ty.kind, self.astconv.allow_ty_infer()) {
                         self.inferred_params.push(ty.span);
-                        tcx.ty_error_misc().into()
+                        Ty::new_misc_error(tcx).into()
                     } else {
                         self.astconv.ast_ty_to_ty(ty).into()
                     }
@@ -512,14 +512,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                 _ => false,
                             }) {
                                 // Avoid ICE #86756 when type error recovery goes awry.
-                                return tcx.ty_error_misc().into();
+                                return Ty::new_misc_error(tcx).into();
                             }
                             tcx.at(self.span).type_of(param.def_id).subst(tcx, substs).into()
                         } else if infer_args {
                             self.astconv.ty_infer(Some(param), self.span).into()
                         } else {
                             // We've already errored above about the mismatch.
-                            tcx.ty_error_misc().into()
+                            Ty::new_misc_error(tcx).into()
                         }
                     }
                     GenericParamDefKind::Const { has_default } => {
@@ -912,7 +912,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             // referencing a single opaque type) get encoded as a type alias that normalization will
             // then actually instantiate the where bounds of.
             let alias_ty = self.tcx().mk_alias_ty(did, substs);
-            self.tcx().mk_alias(ty::Weak, alias_ty)
+            Ty::new_alias(self.tcx(), ty::Weak, alias_ty)
         } else {
             ty.subst(self.tcx(), substs)
         }
@@ -1573,10 +1573,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
                 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                     match *ty.kind() {
-                        ty::Bound(_, bv) => self.tcx.mk_placeholder(ty::PlaceholderType {
-                            universe: self.universe,
-                            bound: bv,
-                        }),
+                        ty::Bound(_, bv) => Ty::new_placeholder(
+                            self.tcx,
+                            ty::PlaceholderType { universe: self.universe, bound: bv },
+                        ),
                         _ => ty.super_fold_with(self),
                     }
                 }
@@ -1665,7 +1665,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     .chain(substs.into_iter().skip(parent_substs.len())),
             );
 
-            let ty = tcx.mk_alias(ty::Inherent, tcx.mk_alias_ty(assoc_item, substs));
+            let ty = Ty::new_alias(tcx, ty::Inherent, tcx.mk_alias_ty(assoc_item, substs));
 
             return Ok(Some((ty, assoc_item)));
         }
@@ -1850,7 +1850,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 &[path_str],
                 item_segment.ident.name,
             );
-            return tcx.ty_error(reported)
+            return Ty::new_error(tcx,reported)
         };
 
         debug!("qpath_to_ty: self_type={:?}", self_ty);
@@ -1873,7 +1873,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         debug!("qpath_to_ty: trait_ref={:?}", trait_ref);
 
-        tcx.mk_projection(item_def_id, item_substs)
+        Ty::new_projection(tcx, item_def_id, item_substs)
     }
 
     pub fn prohibit_generics<'a>(
@@ -2136,7 +2136,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     err.note("`impl Trait` types can't have type parameters");
                 });
                 let substs = self.ast_path_substs_for_ty(span, did, item_segment.0);
-                tcx.mk_opaque(did, substs)
+                Ty::new_opaque(tcx, did, substs)
             }
             Res::Def(
                 DefKind::Enum
@@ -2188,16 +2188,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             var: ty::BoundVar::from_u32(index),
                             kind: ty::BoundTyKind::Param(def_id, name),
                         };
-                        tcx.mk_bound(debruijn, br)
+                        Ty::new_bound(tcx, debruijn, br)
                     }
                     Some(rbv::ResolvedArg::EarlyBound(_)) => {
                         let def_id = def_id.expect_local();
                         let item_def_id = tcx.hir().ty_param_owner(def_id);
                         let generics = tcx.generics_of(item_def_id);
                         let index = generics.param_def_id_to_index[&def_id.to_def_id()];
-                        tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id))
+                        Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id))
                     }
-                    Some(rbv::ResolvedArg::Error(guar)) => tcx.ty_error(guar),
+                    Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar),
                     arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"),
                 }
             }
@@ -2309,7 +2309,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     {
                         err.span_note(impl_.self_ty.span, "not a concrete type");
                     }
-                    tcx.ty_error(err.emit())
+                    Ty::new_error(tcx, err.emit())
                 } else {
                     ty
                 }
@@ -2350,9 +2350,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 match prim_ty {
                     hir::PrimTy::Bool => tcx.types.bool,
                     hir::PrimTy::Char => tcx.types.char,
-                    hir::PrimTy::Int(it) => tcx.mk_mach_int(ty::int_ty(it)),
-                    hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(ty::uint_ty(uit)),
-                    hir::PrimTy::Float(ft) => tcx.mk_mach_float(ty::float_ty(ft)),
+                    hir::PrimTy::Int(it) => Ty::new_int(tcx, ty::int_ty(it)),
+                    hir::PrimTy::Uint(uit) => Ty::new_uint(tcx, ty::uint_ty(uit)),
+                    hir::PrimTy::Float(ft) => Ty::new_float(tcx, ty::float_ty(ft)),
                     hir::PrimTy::Str => tcx.types.str_,
                 }
             }
@@ -2362,7 +2362,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     .sess
                     .delay_span_bug(path.span, "path with `Res::Err` but no error emitted");
                 self.set_tainted_by_errors(e);
-                self.tcx().ty_error(e)
+                Ty::new_error(self.tcx(), e)
             }
             _ => span_bug!(span, "unexpected resolution: {:?}", path.res),
         }
@@ -2387,31 +2387,27 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let tcx = self.tcx();
 
         let result_ty = match &ast_ty.kind {
-            hir::TyKind::Slice(ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)),
+            hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.ast_ty_to_ty(ty)),
             hir::TyKind::Ptr(mt) => {
-                tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl })
+                Ty::new_ptr(tcx, ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl })
             }
             hir::TyKind::Ref(region, mt) => {
                 let r = self.ast_region_to_region(region, None);
                 debug!(?r);
                 let t = self.ast_ty_to_ty_inner(mt.ty, true, false);
-                tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl })
+                Ty::new_ref(tcx, r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl })
             }
             hir::TyKind::Never => tcx.types.never,
             hir::TyKind::Tup(fields) => {
-                tcx.mk_tup_from_iter(fields.iter().map(|t| self.ast_ty_to_ty(t)))
+                Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.ast_ty_to_ty(t)))
             }
             hir::TyKind::BareFn(bf) => {
                 require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span);
 
-                tcx.mk_fn_ptr(self.ty_of_fn(
-                    ast_ty.hir_id,
-                    bf.unsafety,
-                    bf.abi,
-                    bf.decl,
-                    None,
-                    Some(ast_ty),
-                ))
+                Ty::new_fn_ptr(
+                    tcx,
+                    self.ty_of_fn(ast_ty.hir_id, bf.unsafety, bf.abi, bf.decl, None, Some(ast_ty)),
+                )
             }
             hir::TyKind::TraitObject(bounds, lifetime, repr) => {
                 self.maybe_lint_bare_trait(ast_ty, in_path);
@@ -2458,7 +2454,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 let ty = self.ast_ty_to_ty_inner(qself, false, true);
                 self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, qself, segment, false)
                     .map(|(ty, _, _)| ty)
-                    .unwrap_or_else(|guar| tcx.ty_error(guar))
+                    .unwrap_or_else(|guar| Ty::new_error(tcx, guar))
             }
             &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => {
                 let def_id = tcx.require_lang_item(lang_item, Some(span));
@@ -2482,7 +2478,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     }
                 };
 
-                tcx.mk_array_with_const_len(self.ast_ty_to_ty(ty), length)
+                Ty::new_array_with_const_len(tcx, self.ast_ty_to_ty(ty), length)
             }
             hir::TyKind::Typeof(e) => {
                 let ty_erased = tcx.type_of(e.def_id).subst_identity();
@@ -2506,7 +2502,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 // handled specially and will not descend into this routine.
                 self.ty_infer(None, ast_ty.span)
             }
-            hir::TyKind::Err(guar) => tcx.ty_error(*guar),
+            hir::TyKind::Err(guar) => Ty::new_error(tcx, *guar),
         };
 
         self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span);
@@ -2543,7 +2539,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         });
         debug!("impl_trait_ty_to_ty: substs={:?}", substs);
 
-        if in_trait { tcx.mk_projection(def_id, substs) } else { tcx.mk_opaque(def_id, substs) }
+        if in_trait {
+            Ty::new_projection(tcx, def_id, substs)
+        } else {
+            Ty::new_opaque(tcx, def_id, substs)
+        }
     }
 
     pub fn ty_of_arg(&self, ty: &hir::Ty<'_>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
@@ -2612,7 +2612,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     self.ast_ty_to_ty(output)
                 }
             }
-            hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(),
+            hir::FnRetTy::DefaultReturn(..) => Ty::new_unit(tcx,),
         };
 
         debug!(?output_ty);
diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
index 918724e0477..9227ee93451 100644
--- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
@@ -131,7 +131,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 .map(|trait_ref| tcx.def_span(trait_ref));
             let reported =
                 tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
-            return tcx.ty_error(reported);
+            return Ty::new_error(tcx, reported);
         }
 
         // Check that there are no gross object safety violations;
@@ -148,7 +148,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     &object_safety_violations,
                 )
                 .emit();
-                return tcx.ty_error(reported);
+                return Ty::new_error(tcx, reported);
             }
         }
 
@@ -271,10 +271,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         if arg == dummy_self.into() {
                             let param = &generics.params[index];
                             missing_type_params.push(param.name);
-                            return tcx.ty_error_misc().into();
+                            return Ty::new_misc_error(tcx).into();
                         } else if arg.walk().any(|arg| arg == dummy_self.into()) {
                             references_self = true;
-                            return tcx.ty_error_misc().into();
+                            return Ty::new_misc_error(tcx).into();
                         }
                         arg
                     })
@@ -342,7 +342,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             .iter()
                             .map(|arg| {
                                 if arg.walk().any(|arg| arg == dummy_self.into()) {
-                                    return tcx.ty_error(guar).into();
+                                    return Ty::new_error(tcx, guar).into();
                                 }
                                 arg
                             })
@@ -401,7 +401,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         };
         debug!("region_bound: {:?}", region_bound);
 
-        let ty = tcx.mk_dynamic(existential_predicates, region_bound, representation);
+        let ty = Ty::new_dynamic(tcx, existential_predicates, region_bound, representation);
         debug!("trait_object_type: {:?}", ty);
         ty
     }
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index 8aa9a2c2734..c07ac35cba3 100644
--- a/compiler/rustc_hir_analysis/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -148,8 +148,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
             return None;
         }
 
-        let (normalized_ty, obligations) =
-            self.structurally_normalize(tcx.mk_projection(tcx.lang_items().deref_target()?, [ty]))?;
+        let (normalized_ty, obligations) = self.structurally_normalize(Ty::new_projection(
+            tcx,
+            tcx.lang_items().deref_target()?,
+            [ty],
+        ))?;
         debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
         self.state.obligations.extend(obligations);
 
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index d232747b647..270b90fa6b2 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -308,9 +308,9 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
     {
         let substs = InternalSubsts::identity_for_item(tcx, def_id);
         let opaque_identity_ty = if in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() {
-            tcx.mk_projection(def_id.to_def_id(), substs)
+            Ty::new_projection(tcx, def_id.to_def_id(), substs)
         } else {
-            tcx.mk_opaque(def_id.to_def_id(), substs)
+            Ty::new_opaque(tcx, def_id.to_def_id(), substs)
         };
         let mut visitor = ProhibitOpaqueVisitor {
             opaque_identity_ty,
@@ -410,7 +410,7 @@ fn check_opaque_meets_bounds<'tcx>(
     let ocx = ObligationCtxt::new(&infcx);
 
     let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
-    let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
+    let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), substs);
 
     // `ReErased` regions appear in the "parent_substs" of closures/generators.
     // We're ignoring them here and replacing them with fresh region variables.
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 0fa65eff616..2999e1fd89b 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -271,7 +271,7 @@ fn compare_method_predicate_entailment<'tcx>(
         infer::HigherRankedType,
         tcx.fn_sig(impl_m.def_id).subst_identity(),
     );
-    let unnormalized_impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(unnormalized_impl_sig));
+    let unnormalized_impl_fty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(unnormalized_impl_sig));
 
     let norm_cause = ObligationCause::misc(impl_m_span, impl_m_def_id);
     let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig);
@@ -288,7 +288,7 @@ fn compare_method_predicate_entailment<'tcx>(
     // We also have to add the normalized trait signature
     // as we don't normalize during implied bounds computation.
     wf_tys.extend(trait_sig.inputs_and_output.iter());
-    let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
+    let trait_fty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(trait_sig));
 
     debug!("compare_impl_method: trait_fty={:?}", trait_fty);
 
@@ -803,7 +803,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
                     return_span,
                 }) {
                     Ok(ty) => ty,
-                    Err(guar) => tcx.ty_error(guar),
+                    Err(guar) => Ty::new_error(tcx, guar),
                 };
                 collected_tys.insert(def_id, ty::EarlyBinder::bind(ty));
             }
@@ -812,7 +812,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
                     return_span,
                     format!("could not fully resolve: {ty} => {err:?}"),
                 );
-                collected_tys.insert(def_id, ty::EarlyBinder::bind(tcx.ty_error(reported)));
+                collected_tys.insert(def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, reported)));
             }
         }
     }
@@ -916,7 +916,7 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> {
                     _ => arg.try_fold_with(self)?,
                 });
             }
-            Ok(self.tcx.mk_opaque(def_id, self.tcx.mk_substs(&mapped_substs)))
+            Ok(Ty::new_opaque(self.tcx, def_id, self.tcx.mk_substs(&mapped_substs)))
         } else {
             t.try_super_fold_with(self)
         }
@@ -2027,7 +2027,8 @@ pub(super) fn check_type_bounds<'tcx>(
                 let kind = ty::BoundTyKind::Param(param.def_id, param.name);
                 let bound_var = ty::BoundVariableKind::Ty(kind);
                 bound_vars.push(bound_var);
-                tcx.mk_bound(
+                Ty::new_bound(
+                    tcx,
                     ty::INNERMOST,
                     ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
                 )
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 36c468e7789..1248f991cc4 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -11,7 +11,7 @@ use hir::def_id::DefId;
 use rustc_errors::{struct_span_err, DiagnosticMessage};
 use rustc_hir as hir;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
@@ -53,14 +53,14 @@ fn equate_intrinsic_type<'tcx>(
         && gen_count_ok(own_counts.types, n_tps, "type")
         && gen_count_ok(own_counts.consts, 0, "const")
     {
-        let fty = tcx.mk_fn_ptr(sig);
+        let fty = Ty::new_fn_ptr(tcx, sig);
         let it_def_id = it.owner_id.def_id;
         let cause = ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType);
         require_same_types(
             tcx,
             &cause,
             ty::ParamEnv::empty(), // FIXME: do all intrinsics have an empty param env?
-            tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id).subst_identity()),
+            Ty::new_fn_ptr(tcx, tcx.fn_sig(it.owner_id).subst_identity()),
             fty,
         );
     }
@@ -134,7 +134,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir
 /// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`,
 /// and in `library/core/src/intrinsics.rs`.
 pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
-    let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)));
+    let param = |n| Ty::new_param(tcx, n, Symbol::intern(&format!("P{}", n)));
     let intrinsic_id = it.owner_id.to_def_id();
     let intrinsic_name = tcx.item_name(intrinsic_id);
     let name_str = intrinsic_name.as_str();
@@ -156,7 +156,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrEnv },
             );
             let va_list_ty = tcx.type_of(did).subst(tcx, &[region.into()]);
-            (tcx.mk_ref(env_region, ty::TypeAndMut { ty: va_list_ty, mutbl }), va_list_ty)
+            (Ty::new_ref(tcx, env_region, ty::TypeAndMut { ty: va_list_ty, mutbl }), va_list_ty)
         })
     };
 
@@ -168,15 +168,15 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
         let (n_tps, inputs, output) = match split[1] {
             "cxchg" | "cxchgweak" => (
                 1,
-                vec![tcx.mk_mut_ptr(param(0)), param(0), param(0)],
-                tcx.mk_tup(&[param(0), tcx.types.bool]),
+                vec![Ty::new_mut_ptr(tcx, param(0)), param(0), param(0)],
+                Ty::new_tup(tcx, &[param(0), tcx.types.bool]),
             ),
-            "load" => (1, vec![tcx.mk_imm_ptr(param(0))], param(0)),
-            "store" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
+            "load" => (1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)),
+            "store" => (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx)),
 
             "xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" | "min" | "umax"
-            | "umin" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], param(0)),
-            "fence" | "singlethreadfence" => (0, Vec::new(), tcx.mk_unit()),
+            | "umin" => (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], param(0)),
+            "fence" | "singlethreadfence" => (0, Vec::new(), Ty::new_unit(tcx)),
             op => {
                 tcx.sess.emit_err(UnrecognizedAtomicOperation { span: it.span, op });
                 return;
@@ -188,19 +188,19 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
         let (n_tps, inputs, output) = match intrinsic_name {
             sym::abort => (0, Vec::new(), tcx.types.never),
             sym::unreachable => (0, Vec::new(), tcx.types.never),
-            sym::breakpoint => (0, Vec::new(), tcx.mk_unit()),
+            sym::breakpoint => (0, Vec::new(), Ty::new_unit(tcx)),
             sym::size_of | sym::pref_align_of | sym::min_align_of | sym::variant_count => {
                 (1, Vec::new(), tcx.types.usize)
             }
             sym::size_of_val | sym::min_align_of_val => {
-                (1, vec![tcx.mk_imm_ptr(param(0))], tcx.types.usize)
+                (1, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize)
             }
             sym::rustc_peek => (1, vec![param(0)], param(0)),
             sym::caller_location => (0, vec![], tcx.caller_location_ty()),
             sym::assert_inhabited
             | sym::assert_zero_valid
-            | sym::assert_mem_uninitialized_valid => (1, Vec::new(), tcx.mk_unit()),
-            sym::forget => (1, vec![param(0)], tcx.mk_unit()),
+            | sym::assert_mem_uninitialized_valid => (1, Vec::new(), Ty::new_unit(tcx)),
+            sym::forget => (1, vec![param(0)], Ty::new_unit(tcx)),
             sym::transmute | sym::transmute_unchecked => (2, vec![param(0)], param(1)),
             sym::prefetch_read_data
             | sym::prefetch_write_data
@@ -208,75 +208,79 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             | sym::prefetch_write_instruction => (
                 1,
                 vec![
-                    tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
+                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
                     tcx.types.i32,
                 ],
-                tcx.mk_unit(),
+                Ty::new_unit(tcx),
             ),
-            sym::drop_in_place => (1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_unit()),
+            sym::drop_in_place => (1, vec![Ty::new_mut_ptr(tcx, param(0))], Ty::new_unit(tcx)),
             sym::needs_drop => (1, Vec::new(), tcx.types.bool),
 
-            sym::type_name => (1, Vec::new(), tcx.mk_static_str()),
+            sym::type_name => (1, Vec::new(), Ty::new_static_str(tcx)),
             sym::type_id => (1, Vec::new(), tcx.types.u128),
             sym::offset => (2, vec![param(0), param(1)], param(0)),
             sym::arith_offset => (
                 1,
                 vec![
-                    tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
+                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
                     tcx.types.isize,
                 ],
-                tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
+                Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
             ),
             sym::option_payload_ptr => {
                 let option_def_id = tcx.require_lang_item(hir::LangItem::Option, None);
                 let p0 = param(0);
                 (
                     1,
-                    vec![tcx.mk_ptr(ty::TypeAndMut {
-                        ty: tcx.mk_adt(
-                            tcx.adt_def(option_def_id),
-                            tcx.mk_substs_from_iter([ty::GenericArg::from(p0)].into_iter()),
-                        ),
-                        mutbl: hir::Mutability::Not,
-                    })],
-                    tcx.mk_ptr(ty::TypeAndMut { ty: p0, mutbl: hir::Mutability::Not }),
+                    vec![Ty::new_ptr(
+                        tcx,
+                        ty::TypeAndMut {
+                            ty: Ty::new_adt(
+                                tcx,
+                                tcx.adt_def(option_def_id),
+                                tcx.mk_substs_from_iter([ty::GenericArg::from(p0)].into_iter()),
+                            ),
+                            mutbl: hir::Mutability::Not,
+                        },
+                    )],
+                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: p0, mutbl: hir::Mutability::Not }),
                 )
             }
             sym::ptr_mask => (
                 1,
                 vec![
-                    tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
+                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
                     tcx.types.usize,
                 ],
-                tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
+                Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
             ),
 
             sym::copy | sym::copy_nonoverlapping => (
                 1,
                 vec![
-                    tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
-                    tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }),
+                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
+                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }),
                     tcx.types.usize,
                 ],
-                tcx.mk_unit(),
+                Ty::new_unit(tcx),
             ),
             sym::volatile_copy_memory | sym::volatile_copy_nonoverlapping_memory => (
                 1,
                 vec![
-                    tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }),
-                    tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
+                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }),
+                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
                     tcx.types.usize,
                 ],
-                tcx.mk_unit(),
+                Ty::new_unit(tcx),
             ),
             sym::write_bytes | sym::volatile_set_memory => (
                 1,
                 vec![
-                    tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }),
+                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }),
                     tcx.types.u8,
                     tcx.types.usize,
                 ],
-                tcx.mk_unit(),
+                Ty::new_unit(tcx),
             ),
             sym::sqrtf32 => (0, vec![tcx.types.f32], tcx.types.f32),
             sym::sqrtf64 => (0, vec![tcx.types.f64], tcx.types.f64),
@@ -324,10 +328,10 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             sym::roundevenf64 => (0, vec![tcx.types.f64], tcx.types.f64),
 
             sym::volatile_load | sym::unaligned_volatile_load => {
-                (1, vec![tcx.mk_imm_ptr(param(0))], param(0))
+                (1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0))
             }
             sym::volatile_store | sym::unaligned_volatile_store => {
-                (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit())
+                (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx))
             }
 
             sym::ctpop
@@ -339,28 +343,34 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             | sym::bitreverse => (1, vec![param(0)], param(0)),
 
             sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
-                (1, vec![param(0), param(0)], tcx.mk_tup(&[param(0), tcx.types.bool]))
+                (1, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool]))
             }
 
-            sym::ptr_guaranteed_cmp => {
-                (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.u8)
-            }
+            sym::ptr_guaranteed_cmp => (
+                1,
+                vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))],
+                tcx.types.u8,
+            ),
 
             sym::const_allocate => {
-                (0, vec![tcx.types.usize, tcx.types.usize], tcx.mk_mut_ptr(tcx.types.u8))
+                (0, vec![tcx.types.usize, tcx.types.usize], Ty::new_mut_ptr(tcx, tcx.types.u8))
             }
             sym::const_deallocate => (
                 0,
-                vec![tcx.mk_mut_ptr(tcx.types.u8), tcx.types.usize, tcx.types.usize],
-                tcx.mk_unit(),
+                vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize],
+                Ty::new_unit(tcx),
             ),
 
-            sym::ptr_offset_from => {
-                (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
-            }
-            sym::ptr_offset_from_unsigned => {
-                (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.usize)
-            }
+            sym::ptr_offset_from => (
+                1,
+                vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))],
+                tcx.types.isize,
+            ),
+            sym::ptr_offset_from_unsigned => (
+                1,
+                vec![Ty::new_imm_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0))],
+                tcx.types.usize,
+            ),
             sym::unchecked_div | sym::unchecked_rem | sym::exact_div => {
                 (1, vec![param(0), param(0)], param(0))
             }
@@ -379,12 +389,14 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             }
             sym::float_to_int_unchecked => (2, vec![param(0)], param(1)),
 
-            sym::assume => (0, vec![tcx.types.bool], tcx.mk_unit()),
+            sym::assume => (0, vec![tcx.types.bool], Ty::new_unit(tcx)),
             sym::likely => (0, vec![tcx.types.bool], tcx.types.bool),
             sym::unlikely => (0, vec![tcx.types.bool], tcx.types.bool),
 
-            sym::read_via_copy => (1, vec![tcx.mk_imm_ptr(param(0))], param(0)),
-            sym::write_via_move => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
+            sym::read_via_copy => (1, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)),
+            sym::write_via_move => {
+                (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx))
+            }
 
             sym::discriminant_value => {
                 let assoc_items = tcx.associated_item_def_ids(
@@ -395,48 +407,47 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) };
                 (
                     1,
-                    vec![
-                        tcx.mk_imm_ref(
-                            ty::Region::new_late_bound(tcx, ty::INNERMOST, br),
-                            param(0),
-                        ),
-                    ],
-                    tcx.mk_projection(discriminant_def_id, tcx.mk_substs(&[param(0).into()])),
+                    vec![Ty::new_imm_ref(
+                        tcx,
+                        ty::Region::new_late_bound(tcx, ty::INNERMOST, br),
+                        param(0),
+                    )],
+                    Ty::new_projection(tcx, discriminant_def_id, tcx.mk_substs(&[param(0).into()])),
                 )
             }
 
             kw::Try => {
-                let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);
+                let mut_u8 = Ty::new_mut_ptr(tcx, tcx.types.u8);
                 let try_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig(
                     [mut_u8],
-                    tcx.mk_unit(),
+                    Ty::new_unit(tcx),
                     false,
                     hir::Unsafety::Normal,
                     Abi::Rust,
                 ));
                 let catch_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig(
                     [mut_u8, mut_u8],
-                    tcx.mk_unit(),
+                    Ty::new_unit(tcx),
                     false,
                     hir::Unsafety::Normal,
                     Abi::Rust,
                 ));
                 (
                     0,
-                    vec![tcx.mk_fn_ptr(try_fn_ty), mut_u8, tcx.mk_fn_ptr(catch_fn_ty)],
+                    vec![Ty::new_fn_ptr(tcx, try_fn_ty), mut_u8, Ty::new_fn_ptr(tcx, catch_fn_ty)],
                     tcx.types.i32,
                 )
             }
 
             sym::va_start | sym::va_end => match mk_va_list_ty(hir::Mutability::Mut) {
-                Some((va_list_ref_ty, _)) => (0, vec![va_list_ref_ty], tcx.mk_unit()),
+                Some((va_list_ref_ty, _)) => (0, vec![va_list_ref_ty], Ty::new_unit(tcx)),
                 None => bug!("`va_list` language item needed for C-variadic intrinsics"),
             },
 
             sym::va_copy => match mk_va_list_ty(hir::Mutability::Not) {
                 Some((va_list_ref_ty, va_list_ty)) => {
-                    let va_list_ptr_ty = tcx.mk_mut_ptr(va_list_ty);
-                    (0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.mk_unit())
+                    let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty);
+                    (0, vec![va_list_ptr_ty, va_list_ref_ty], Ty::new_unit(tcx))
                 }
                 None => bug!("`va_list` language item needed for C-variadic intrinsics"),
             },
@@ -446,12 +457,17 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 None => bug!("`va_list` language item needed for C-variadic intrinsics"),
             },
 
-            sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
+            sym::nontemporal_store => {
+                (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx))
+            }
 
             sym::raw_eq => {
                 let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) };
-                let param_ty =
-                    tcx.mk_imm_ref(ty::Region::new_late_bound(tcx, ty::INNERMOST, br), param(0));
+                let param_ty = Ty::new_imm_ref(
+                    tcx,
+                    ty::Region::new_late_bound(tcx, ty::INNERMOST, br),
+                    param(0),
+                );
                 (1, vec![param_ty; 2], tcx.types.bool)
             }
 
@@ -460,7 +476,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)),
 
             sym::vtable_size | sym::vtable_align => {
-                (0, vec![tcx.mk_imm_ptr(tcx.mk_unit())], tcx.types.usize)
+                (0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize)
             }
 
             other => {
@@ -479,7 +495,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
 pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
     let param = |n| {
         let name = Symbol::intern(&format!("P{}", n));
-        tcx.mk_ty_param(n, name)
+        Ty::new_param(tcx, n, name)
     };
 
     let name = it.ident.name;
@@ -521,7 +537,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
         sym::simd_fpowi => (1, vec![param(0), tcx.types.i32], param(0)),
         sym::simd_fma => (1, vec![param(0), param(0), param(0)], param(0)),
         sym::simd_gather => (3, vec![param(0), param(1), param(2)], param(0)),
-        sym::simd_scatter => (3, vec![param(0), param(1), param(2)], tcx.mk_unit()),
+        sym::simd_scatter => (3, vec![param(0), param(1), param(2)], Ty::new_unit(tcx)),
         sym::simd_insert => (2, vec![param(0), tcx.types.u32, param(1)], param(0)),
         sym::simd_extract => (2, vec![param(0), tcx.types.u32], param(1)),
         sym::simd_cast
@@ -550,7 +566,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
         name if name.as_str().starts_with("simd_shuffle") => {
             match name.as_str()["simd_shuffle".len()..].parse() {
                 Ok(n) => {
-                    let params = vec![param(0), param(0), tcx.mk_array(tcx.types.u32, n)];
+                    let params = vec![param(0), param(0), Ty::new_array(tcx, tcx.types.u32, n)];
                     (2, params, param(1))
                 }
                 Err(_) => {
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 506fdccd6c2..7a625dd5932 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -561,7 +561,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
                 // our example, the type was `Self`, which will also be
                 // `Self` in the GAT.
                 let ty_param = gat_generics.param_at(*ty_idx, tcx);
-                let ty_param = tcx.mk_ty_param(ty_param.index, ty_param.name);
+                let ty_param = Ty::new_param(tcx, ty_param.index, ty_param.name);
                 // Same for the region. In our example, 'a corresponds
                 // to the 'me parameter.
                 let region_param = gat_generics.param_at(*region_a_idx, tcx);
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 2441c8667d4..79cc43edff1 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -336,15 +336,17 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
             infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
             let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
             let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b };
-            check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
+            check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))
         }
 
         (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => {
             let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
-            check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
+            check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))
         }
 
-        (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)),
+        (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => {
+            check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))
+        }
 
         (&ty::Adt(def_a, substs_a), &ty::Adt(def_b, substs_b))
             if def_a.is_struct() && def_b.is_struct() =>
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index eb299a1ea79..025bab14021 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -343,7 +343,7 @@ fn emit_orphan_check_error<'tcx>(
                     // That way if we had `Vec<MyType>`, we will properly attribute the
                     // problem to `Vec<T>` and avoid confusing the user if they were to see
                     // `MyType` in the error.
-                    ty::Adt(def, _) => tcx.mk_adt(*def, ty::List::empty()),
+                    ty::Adt(def, _) => Ty::new_adt(tcx, *def, ty::List::empty()),
                     _ => ty,
                 };
                 let msg = |ty: &str, postfix: &str| {
@@ -605,7 +605,9 @@ fn fast_reject_auto_impl<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, self_ty:
     }
 
     let self_ty_root = match self_ty.kind() {
-        ty::Adt(def, _) => tcx.mk_adt(*def, InternalSubsts::identity_for_item(tcx, def.did())),
+        ty::Adt(def, _) => {
+            Ty::new_adt(tcx, *def, InternalSubsts::identity_for_item(tcx, def.did()))
+        }
         _ => unimplemented!("unexpected self ty {:?}", self_ty),
     };
 
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 0339e79a278..f47df4f215b 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -380,7 +380,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
     }
 
     fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
-        self.tcx().ty_error_with_message(span, "bad placeholder type")
+        Ty::new_error_with_message(self.tcx(), span, "bad placeholder type")
     }
 
     fn ct_infer(&self, ty: Ty<'tcx>, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
@@ -407,7 +407,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
                 item_segment,
                 trait_ref.substs,
             );
-            self.tcx().mk_projection(item_def_id, item_substs)
+            Ty::new_projection(self.tcx(), item_def_id, item_substs)
         } else {
             // There are no late-bound regions; we can just ignore the binder.
             let (mut mpart_sugg, mut inferred_sugg) = (None, None);
@@ -471,14 +471,15 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
                 }
                 _ => {}
             }
-            self.tcx().ty_error(self.tcx().sess.emit_err(
-                errors::AssociatedTypeTraitUninferredGenericParams {
+            Ty::new_error(
+                self.tcx(),
+                self.tcx().sess.emit_err(errors::AssociatedTypeTraitUninferredGenericParams {
                     span,
                     inferred_sugg,
                     bound,
                     mpart_sugg,
-                },
-            ))
+                }),
+            )
         }
     }
 
@@ -1239,7 +1240,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
             } else {
                 ty::Binder::dummy(tcx.mk_fn_sig(
                     fn_sig.inputs().iter().copied(),
-                    tcx.ty_error(guar),
+                    Ty::new_error(tcx, guar),
                     fn_sig.c_variadic,
                     fn_sig.unsafety,
                     fn_sig.abi,
@@ -1332,7 +1333,7 @@ fn suggest_impl_trait<'tcx>(
         let item_ty = ocx.normalize(
             &ObligationCause::misc(span, def_id),
             param_env,
-            tcx.mk_projection(assoc_item_def_id, substs),
+            Ty::new_projection(tcx, assoc_item_def_id, substs),
         );
         // FIXME(compiler-errors): We may benefit from resolving regions here.
         if ocx.select_where_possible().is_empty()
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 8b3f98493c1..57f74172ed0 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -20,7 +20,8 @@ fn associated_type_bounds<'tcx>(
     ast_bounds: &'tcx [hir::GenericBound<'tcx>],
     span: Span,
 ) -> &'tcx [(ty::Clause<'tcx>, Span)] {
-    let item_ty = tcx.mk_projection(
+    let item_ty = Ty::new_projection(
+        tcx,
         assoc_item_def_id.to_def_id(),
         InternalSubsts::identity_for_item(tcx, assoc_item_def_id),
     );
@@ -91,7 +92,8 @@ pub(super) fn explicit_item_bounds(
                 tcx,
                 opaque_def_id.expect_local(),
                 opaque_ty.bounds,
-                tcx.mk_projection(
+                Ty::new_projection(
+                    tcx,
                     def_id.to_def_id(),
                     ty::InternalSubsts::identity_for_item(tcx, def_id),
                 ),
@@ -117,9 +119,9 @@ pub(super) fn explicit_item_bounds(
         }) => {
             let substs = InternalSubsts::identity_for_item(tcx, def_id);
             let item_ty = if *in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() {
-                tcx.mk_projection(def_id.to_def_id(), substs)
+                Ty::new_projection(tcx, def_id.to_def_id(), substs)
             } else {
-                tcx.mk_opaque(def_id.to_def_id(), substs)
+                Ty::new_opaque(tcx, def_id.to_def_id(), substs)
             };
             opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
         }
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index df2c24a6001..12936664130 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -719,6 +719,7 @@ pub(super) fn type_param_predicates(
     (item_def_id, def_id, assoc_name): (LocalDefId, LocalDefId, Ident),
 ) -> ty::GenericPredicates<'_> {
     use rustc_hir::*;
+    use rustc_middle::ty::Ty;
 
     // In the AST, bounds can derive from two places. Either
     // written inline like `<T: Foo>` or in a where-clause like
@@ -728,7 +729,7 @@ pub(super) fn type_param_predicates(
     let param_owner = tcx.hir().ty_param_owner(def_id);
     let generics = tcx.generics_of(param_owner);
     let index = generics.param_def_id_to_index[&def_id.to_def_id()];
-    let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id));
+    let ty = Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id));
 
     // Don't look for bounds where the type parameter isn't in scope.
     let parent = if item_def_id == param_owner {
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index bd92ee4b550..3755342aef5 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -16,6 +16,7 @@ mod opaque;
 
 fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
     use hir::*;
+    use rustc_middle::ty::Ty;
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
 
     let Node::AnonConst(_) = tcx.hir().get(hir_id) else { panic!() };
@@ -25,13 +26,13 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
 
     let (generics, arg_idx) = match parent_node {
         // Easy case: arrays repeat expressions.
-        Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
+        Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. })
         | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
             if constant.hir_id() == hir_id =>
         {
             return tcx.types.usize
         }
-        Node::Ty(&Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => {
+        Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => {
             return tcx.typeck(def_id).node_type(e.hir_id)
         }
         Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
@@ -67,7 +68,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
             ) =>
         {
             let Some(trait_def_id) = trait_ref.trait_def_id() else {
-                return tcx.ty_error_with_message(tcx.def_span(def_id), "Could not find trait");
+                return Ty::new_error_with_message(tcx,tcx.def_span(def_id), "Could not find trait");
             };
             let assoc_items = tcx.associated_items(trait_def_id);
             let assoc_item = assoc_items.find_by_name_and_kind(
@@ -79,7 +80,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
                     .expect("const parameter types cannot be generic")
             } else {
                 // FIXME(associated_const_equality): add a useful error message here.
-                tcx.ty_error_with_message(tcx.def_span(def_id), "Could not find associated const on trait")
+                Ty::new_error_with_message(tcx,tcx.def_span(def_id), "Could not find associated const on trait")
             }
         }
 
@@ -99,7 +100,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
         // arm would handle this.
         //
         // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU
-        Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => {
+        Node::Ty(hir_ty @ hir::Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => {
             // Find the Item containing the associated type so we can create an ItemCtxt.
             // Using the ItemCtxt convert the HIR for the unresolved assoc type into a
             // ty which is a fully resolved projection.
@@ -137,7 +138,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
                 (generics, arg_index)
             } else {
                 // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
-                return tcx.ty_error_with_message(
+                return Ty::new_error_with_message(tcx,
                     tcx.def_span(def_id),
                     "unexpected non-GAT usage of an anon const",
                 );
@@ -154,7 +155,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
             // As there is no relevant param for `def_id`, we simply return
             // `None` here.
             let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else {
-                return tcx.ty_error_with_message(
+                return Ty::new_error_with_message(tcx,
                     tcx.def_span(def_id),
                     format!("unable to find type-dependent def for {:?}", parent_node_id),
                 );
@@ -174,12 +175,12 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
             (tcx.generics_of(type_dependent_def), idx)
         }
 
-        Node::Ty(&Ty { kind: TyKind::Path(_), .. })
+        Node::Ty(&hir::Ty { kind: TyKind::Path(_), .. })
         | Node::Expr(&Expr { kind: ExprKind::Path(_) | ExprKind::Struct(..), .. })
         | Node::TraitRef(..)
         | Node::Pat(_) => {
             let path = match parent_node {
-                Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
+                Node::Ty(&hir::Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
                 | Node::TraitRef(&TraitRef { path, .. }) => &*path,
                 Node::Expr(&Expr {
                     kind:
@@ -195,14 +196,14 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
                     if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
                         path
                     } else {
-                        return tcx.ty_error_with_message(
+                        return Ty::new_error_with_message(tcx,
                             tcx.def_span(def_id),
                             format!("unable to find const parent for {} in pat {:?}", hir_id, pat),
                         );
                     }
                 }
                 _ => {
-                    return tcx.ty_error_with_message(
+                    return Ty::new_error_with_message(tcx,
                         tcx.def_span(def_id),
                         format!("unexpected const parent path {:?}", parent_node),
                     );
@@ -224,7 +225,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
                     .position(|ct| ct.hir_id == hir_id)
                     .map(|idx| (idx, seg)))
             }) else {
-                return tcx.ty_error_with_message(
+                return Ty::new_error_with_message(tcx,
                     tcx.def_span(def_id),
                     "no arg matching AnonConst in path",
                 );
@@ -233,7 +234,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
             let generics = match tcx.res_generics_def_id(segment.res) {
                 Some(def_id) => tcx.generics_of(def_id),
                 None => {
-                    return tcx.ty_error_with_message(
+                    return Ty::new_error_with_message(tcx,
                         tcx.def_span(def_id),
                         format!("unexpected anon const res {:?} in path: {:?}", segment.res, path),
                     );
@@ -243,7 +244,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
             (generics, arg_index)
         }
 
-        _ => return tcx.ty_error_with_message(
+        _ => return Ty::new_error_with_message(tcx,
             tcx.def_span(def_id),
             format!("unexpected const parent in type_of(): {parent_node:?}"),
         ),
@@ -269,7 +270,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
     {
         tcx.type_of(param_def_id).no_bound_vars().expect("const parameter types cannot be generic")
     } else {
-        return tcx.ty_error_with_message(
+        return Ty::new_error_with_message(
+            tcx,
             tcx.def_span(def_id),
             format!("const generic parameter not found in {generics:?} at position {arg_idx:?}"),
         );
@@ -305,6 +307,9 @@ fn get_path_containing_arg_in_pat<'hir>(
 }
 
 pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty<'_>> {
+    use rustc_hir::*;
+    use rustc_middle::ty::Ty;
+
     // If we are computing `type_of` the synthesized associated type for an RPITIT in the impl
     // side, use `collect_return_position_impl_trait_in_trait_tys` to infer the value of the
     // associated type in the impl.
@@ -317,7 +322,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
                 return map[&assoc_item.trait_item_def_id.unwrap()];
             }
             Err(_) => {
-                return ty::EarlyBinder::bind(tcx.ty_error_with_message(
+                return ty::EarlyBinder::bind(Ty::new_error_with_message(
+                    tcx,
                     DUMMY_SP,
                     "Could not collect return position impl trait in trait tys",
                 ));
@@ -325,8 +331,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
         }
     }
 
-    use rustc_hir::*;
-
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
 
     let icx = ItemCtxt::new(tcx, def_id);
@@ -335,7 +339,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
         Node::TraitItem(item) => match item.kind {
             TraitItemKind::Fn(..) => {
                 let substs = InternalSubsts::identity_for_item(tcx, def_id);
-                tcx.mk_fn_def(def_id.to_def_id(), substs)
+                Ty::new_fn_def(tcx, def_id.to_def_id(), substs)
             }
             TraitItemKind::Const(ty, body_id) => body_id
                 .and_then(|body_id| {
@@ -360,7 +364,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
         Node::ImplItem(item) => match item.kind {
             ImplItemKind::Fn(..) => {
                 let substs = InternalSubsts::identity_for_item(tcx, def_id);
-                tcx.mk_fn_def(def_id.to_def_id(), substs)
+                Ty::new_fn_def(tcx, def_id.to_def_id(), substs)
             }
             ImplItemKind::Const(ty, body_id) => {
                 if is_suggestable_infer_ty(ty) {
@@ -417,18 +421,18 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
                             span: spans.into(),
                             note: (),
                         });
-                        tcx.ty_error(guar)
+                        Ty::new_error(tcx, guar)
                     }
                     _ => icx.to_ty(*self_ty),
                 },
                 ItemKind::Fn(..) => {
                     let substs = InternalSubsts::identity_for_item(tcx, def_id);
-                    tcx.mk_fn_def(def_id.to_def_id(), substs)
+                    Ty::new_fn_def(tcx, def_id.to_def_id(), substs)
                 }
                 ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
                     let def = tcx.adt_def(def_id);
                     let substs = InternalSubsts::identity_for_item(tcx, def_id);
-                    tcx.mk_adt(def, substs)
+                    Ty::new_adt(tcx, def, substs)
                 }
                 ItemKind::OpaqueTy(OpaqueTy {
                     origin: hir::OpaqueTyOrigin::TyAlias { .. },
@@ -469,10 +473,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
         Node::ForeignItem(foreign_item) => match foreign_item.kind {
             ForeignItemKind::Fn(..) => {
                 let substs = InternalSubsts::identity_for_item(tcx, def_id);
-                tcx.mk_fn_def(def_id.to_def_id(), substs)
+                Ty::new_fn_def(tcx, def_id.to_def_id(), substs)
             }
             ForeignItemKind::Static(t, _) => icx.to_ty(t),
-            ForeignItemKind::Type => tcx.mk_foreign(def_id.to_def_id()),
+            ForeignItemKind::Type => Ty::new_foreign(tcx, def_id.to_def_id()),
         },
 
         Node::Ctor(def) | Node::Variant(Variant { data: def, .. }) => match def {
@@ -481,7 +485,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
             }
             VariantData::Tuple(..) => {
                 let substs = InternalSubsts::identity_for_item(tcx, def_id);
-                tcx.mk_fn_def(def_id.to_def_id(), substs)
+                Ty::new_fn_def(tcx, def_id.to_def_id(), substs)
             }
         },
 
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index 4d96a7ff4c3..f4779a3f265 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -84,7 +84,7 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
                 _ => "item",
             },
         });
-        tcx.ty_error(reported)
+        Ty::new_error(tcx, reported)
     }
 }
 
@@ -128,7 +128,8 @@ impl TaitConstraintLocator<'_> {
         // ```
         let tables = self.tcx.typeck(item_def_id);
         if let Some(guar) = tables.tainted_by_errors {
-            self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error(guar) });
+            self.found =
+                Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) });
             return;
         }
 
@@ -162,7 +163,7 @@ impl TaitConstraintLocator<'_> {
             if let Some(prev) = &mut self.found {
                 if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
                     let guar = prev.report_mismatch(&concrete_type, self.def_id, self.tcx).emit();
-                    prev.ty = self.tcx.ty_error(guar);
+                    prev.ty = Ty::new_error(self.tcx, guar);
                 }
             } else {
                 self.found = Some(concrete_type);
@@ -258,7 +259,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
         if let Some(guar) = tables.tainted_by_errors {
             // Some error in the owner fn prevented us from populating
             // the `concrete_opaque_types` table.
-            tcx.ty_error(guar)
+            Ty::new_error(tcx, guar)
         } else {
             // Fall back to the RPIT we inferred during HIR typeck
             if let Some(hir_opaque_ty) = hir_opaque_ty {
@@ -270,7 +271,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
                 // so we can just make the hidden type be `!`.
                 // For backwards compatibility reasons, we fall back to
                 // `()` until we the diverging default is changed.
-                tcx.mk_diverging_default()
+                Ty::new_diverging_default(tcx)
             }
         }
     }
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index d2a1b1c1a42..a68832d96a6 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -319,16 +319,19 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         expected_return_type = main_fnsig.output();
     } else {
         // standard () main return type
-        expected_return_type = ty::Binder::dummy(tcx.mk_unit());
+        expected_return_type = ty::Binder::dummy(Ty::new_unit(tcx));
     }
 
     if error {
         return;
     }
 
-    let se_ty = tcx.mk_fn_ptr(expected_return_type.map_bound(|expected_return_type| {
-        tcx.mk_fn_sig([], expected_return_type, false, hir::Unsafety::Normal, Abi::Rust)
-    }));
+    let se_ty = Ty::new_fn_ptr(
+        tcx,
+        expected_return_type.map_bound(|expected_return_type| {
+            tcx.mk_fn_sig([], expected_return_type, false, hir::Unsafety::Normal, Abi::Rust)
+        }),
+    );
 
     require_same_types(
         tcx,
@@ -339,7 +342,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         ),
         param_env,
         se_ty,
-        tcx.mk_fn_ptr(main_fnsig),
+        Ty::new_fn_ptr(tcx, main_fnsig),
     );
 }
 fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
@@ -397,13 +400,16 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
                 }
             }
 
-            let se_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig(
-                [tcx.types.isize, tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))],
-                tcx.types.isize,
-                false,
-                hir::Unsafety::Normal,
-                Abi::Rust,
-            )));
+            let se_ty = Ty::new_fn_ptr(
+                tcx,
+                ty::Binder::dummy(tcx.mk_fn_sig(
+                    [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))],
+                    tcx.types.isize,
+                    false,
+                    hir::Unsafety::Normal,
+                    Abi::Rust,
+                )),
+            );
 
             require_same_types(
                 tcx,
@@ -414,7 +420,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
                 ),
                 ty::ParamEnv::empty(), // start should not have any where bounds.
                 se_ty,
-                tcx.mk_fn_ptr(tcx.fn_sig(start_def_id).subst_identity()),
+                Ty::new_fn_ptr(tcx, tcx.fn_sig(start_def_id).subst_identity()),
             );
         }
         _ => {
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index c7fa27da1ac..e8720a5da02 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -65,7 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // us to give better error messages (pointing to a usually better
                 // arm for inconsistent arms or to the whole match when a `()` type
                 // is required).
-                Expectation::ExpectHasType(ety) if ety != self.tcx.mk_unit() => ety,
+                Expectation::ExpectHasType(ety) if ety != Ty::new_unit(self.tcx) => ety,
                 _ => self.next_ty_var(TypeVariableOrigin {
                     kind: TypeVariableOriginKind::MiscVariable,
                     span: expr.span,
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index ed9fe8fc856..f306653c1ab 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -233,12 +233,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let Some(trait_def_id) = opt_trait_def_id else { continue };
 
             let opt_input_type = opt_arg_exprs.map(|arg_exprs| {
-                self.tcx.mk_tup_from_iter(arg_exprs.iter().map(|e| {
-                    self.next_ty_var(TypeVariableOrigin {
-                        kind: TypeVariableOriginKind::TypeInference,
-                        span: e.span,
-                    })
-                }))
+                Ty::new_tup_from_iter(
+                    self.tcx,
+                    arg_exprs.iter().map(|e| {
+                        self.next_ty_var(TypeVariableOrigin {
+                            kind: TypeVariableOriginKind::TypeInference,
+                            span: e.span,
+                        })
+                    }),
+                )
             });
 
             if let Some(ok) = self.lookup_method_in_trait(
@@ -435,7 +438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 let err = self.report_invalid_callee(call_expr, callee_expr, callee_ty, arg_exprs);
 
-                return self.tcx.ty_error(err);
+                return Ty::new_error(self.tcx, err);
             }
         };
 
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index f1b3d13c24d..71799387458 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -393,7 +393,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                         && fcx
                             .try_coerce(
                                 self.expr,
-                                fcx.tcx.mk_ref(
+                                Ty::new_ref(fcx.tcx,
                                     fcx.tcx.lifetimes.re_erased,
                                     TypeAndMut { ty: expr_ty, mutbl },
                                 ),
@@ -410,7 +410,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                         && fcx
                             .try_coerce(
                                 self.expr,
-                                fcx.tcx.mk_ref(
+                                Ty::new_ref(fcx.tcx,
                                     expr_reg,
                                     TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut },
                                 ),
@@ -428,7 +428,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                         && fcx
                             .try_coerce(
                                 self.expr,
-                                fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
+                                Ty::new_ref(fcx.tcx,reg, TypeAndMut { ty: self.expr_ty, mutbl }),
                                 self.cast_ty,
                                 AllowTwoPhase::No,
                                 None,
@@ -441,7 +441,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     && fcx
                         .try_coerce(
                             self.expr,
-                            fcx.tcx.mk_ref(
+                            Ty::new_ref(fcx.tcx,
                                 fcx.tcx.lifetimes.re_erased,
                                 TypeAndMut { ty: self.expr_ty, mutbl },
                             ),
@@ -765,7 +765,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                         let res = fcx.try_coerce(
                             self.expr,
                             self.expr_ty,
-                            fcx.tcx.mk_fn_ptr(f),
+                            Ty::new_fn_ptr(fcx.tcx, f),
                             AllowTwoPhase::No,
                             None,
                         );
@@ -957,7 +957,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 // from a region pointer to a vector.
 
                 // Coerce to a raw pointer so that we generate AddressOf in MIR.
-                let array_ptr_type = fcx.tcx.mk_ptr(m_expr);
+                let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr);
                 fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
                     .unwrap_or_else(|_| {
                         bug!(
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 0a1b639af51..8b57e311fc0 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -62,11 +62,11 @@ pub(super) fn check_fn<'a, 'tcx>(
             fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
             yield_ty
         } else {
-            tcx.mk_unit()
+            Ty::new_unit(tcx,)
         };
 
         // Resume type defaults to `()` if the generator has no argument.
-        let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit());
+        let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| Ty::new_unit(tcx,));
 
         fcx.resume_yield_tys = Some((resume_ty, yield_ty));
     }
@@ -256,10 +256,10 @@ fn check_lang_start_fn<'tcx>(
         // for example `start`'s generic should be a type parameter
         let generics = tcx.generics_of(def_id);
         let fn_generic = generics.param_at(0, tcx);
-        let generic_ty = tcx.mk_ty_param(fn_generic.index, fn_generic.name);
+        let generic_ty = Ty::new_param(tcx, fn_generic.index, fn_generic.name);
         let expected_fn_sig =
             tcx.mk_fn_sig([], generic_ty, false, hir::Unsafety::Normal, Abi::Rust);
-        let expected_ty = tcx.mk_fn_ptr(Binder::dummy(expected_fn_sig));
+        let expected_ty = Ty::new_fn_ptr(tcx, Binder::dummy(expected_fn_sig));
 
         // we emit the same error to suggest changing the arg no matter what's wrong with the arg
         let emit_main_fn_arg_err = || {
@@ -316,9 +316,9 @@ fn check_lang_start_fn<'tcx>(
 
         if !argv_is_okay {
             let inner_ptr_ty =
-                tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: tcx.types.u8 });
+                Ty::new_ptr(tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: tcx.types.u8 });
             let expected_ty =
-                tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: inner_ptr_ty });
+                Ty::new_ptr(tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: inner_ptr_ty });
             tcx.sess.emit_err(LangStartIncorrectParam {
                 param_span: decl.inputs[2].span,
                 param_num: 3,
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index c64b64e925a..78a9ac49de2 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -117,7 +117,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 },
             );
 
-            return self.tcx.mk_generator(
+            return Ty::new_generator(
+                self.tcx,
                 expr_def_id.to_def_id(),
                 generator_substs.substs,
                 movability,
@@ -128,7 +129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // the `closures` table.
         let sig = bound_sig.map_bound(|sig| {
             self.tcx.mk_fn_sig(
-                [self.tcx.mk_tup(sig.inputs())],
+                [Ty::new_tup(self.tcx, sig.inputs())],
                 sig.output(),
                 sig.c_variadic,
                 sig.unsafety,
@@ -155,12 +156,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ty::ClosureSubstsParts {
                 parent_substs,
                 closure_kind_ty,
-                closure_sig_as_fn_ptr_ty: self.tcx.mk_fn_ptr(sig),
+                closure_sig_as_fn_ptr_ty: Ty::new_fn_ptr(self.tcx, sig),
                 tupled_upvars_ty,
             },
         );
 
-        self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs)
+        Ty::new_closure(self.tcx, expr_def_id.to_def_id(), closure_substs.substs)
     }
 
     /// Given the expected type, figures out what it can about this closure we
@@ -190,7 +191,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 (sig, kind)
             }
             ty::Infer(ty::TyVar(vid)) => self.deduce_closure_signature_from_predicates(
-                self.tcx.mk_ty_var(self.root_var(vid)),
+                Ty::new_var(self.tcx, self.root_var(vid)),
                 self.obligations_for_self_ty(vid).map(|obl| (obl.predicate, obl.cause.span)),
             ),
             ty::FnPtr(sig) => {
@@ -806,7 +807,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         guar: ErrorGuaranteed,
     ) -> ty::PolyFnSig<'tcx> {
         let astconv: &dyn AstConv<'_> = self;
-        let err_ty = self.tcx.ty_error(guar);
+        let err_ty = Ty::new_error(self.tcx, guar);
 
         let supplied_arguments = decl.inputs.iter().map(|a| {
             // Convert the types that the user supplied (if any), but ignore them.
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 9a037f7110e..ea6ae094f09 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -192,7 +192,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             let _ = self.commit_if_ok(|_| {
                 self.at(&self.cause, self.param_env).eq(DefineOpaqueTypes::Yes, a, b)
             });
-            return success(vec![], self.fcx.tcx.ty_error(guar), vec![]);
+            return success(vec![], Ty::new_error(self.fcx.tcx, guar), vec![]);
         }
 
         // Coercing from `!` to any type is allowed:
@@ -440,7 +440,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 }
                 r_borrow_var.unwrap()
             };
-            let derefd_ty_a = self.tcx.mk_ref(
+            let derefd_ty_a = Ty::new_ref(
+                self.tcx,
                 r,
                 TypeAndMut {
                     ty: referent_ty,
@@ -558,9 +559,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                     Adjustment { kind: Adjust::Deref(None), target: ty_a },
                     Adjustment {
                         kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)),
-                        target: self
-                            .tcx
-                            .mk_ref(r_borrow, ty::TypeAndMut { mutbl: mutbl_b, ty: ty_a }),
+                        target: Ty::new_ref(
+                            self.tcx,
+                            r_borrow,
+                            ty::TypeAndMut { mutbl: mutbl_b, ty: ty_a },
+                        ),
                     },
                 ))
             }
@@ -571,7 +574,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                     Adjustment { kind: Adjust::Deref(None), target: ty_a },
                     Adjustment {
                         kind: Adjust::Borrow(AutoBorrow::RawPtr(mt_b)),
-                        target: self.tcx.mk_ptr(ty::TypeAndMut { mutbl: mt_b, ty: ty_a }),
+                        target: Ty::new_ptr(self.tcx, ty::TypeAndMut { mutbl: mt_b, ty: ty_a }),
                     },
                 ))
             }
@@ -883,7 +886,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                     self.at(&self.cause, self.param_env).normalize(a_sig);
                 obligations.extend(o1);
 
-                let a_fn_pointer = self.tcx.mk_fn_ptr(a_sig);
+                let a_fn_pointer = Ty::new_fn_ptr(self.tcx, a_sig);
                 let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn(
                     a_fn_pointer,
                     a_sig,
@@ -945,7 +948,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 let closure_sig = substs_a.as_closure().sig();
                 let unsafety = fn_ty.unsafety();
                 let pointer_ty =
-                    self.tcx.mk_fn_ptr(self.tcx.signature_unclosure(closure_sig, unsafety));
+                    Ty::new_fn_ptr(self.tcx, self.tcx.signature_unclosure(closure_sig, unsafety));
                 debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty);
                 self.unify_and(
                     pointer_ty,
@@ -973,7 +976,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         coerce_mutbls(mt_a.mutbl, mutbl_b)?;
 
         // Check that the types which they point at are compatible.
-        let a_unsafe = self.tcx.mk_ptr(ty::TypeAndMut { mutbl: mutbl_b, ty: mt_a.ty });
+        let a_unsafe = Ty::new_ptr(self.tcx, ty::TypeAndMut { mutbl: mutbl_b, ty: mt_a.ty });
         // Although references and unsafe ptrs have the same
         // representation, we still register an Adjust::DerefRef so that
         // regionck knows that the region for `a` must be valid here.
@@ -1015,7 +1018,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let (adjustments, _) = self.register_infer_ok_obligations(ok);
         self.apply_adjustments(expr, adjustments);
-        Ok(if let Err(guar) = expr_ty.error_reported() { self.tcx.ty_error(guar) } else { target })
+        Ok(if let Err(guar) = expr_ty.error_reported() {
+            Ty::new_error(self.tcx, guar)
+        } else {
+            target
+        })
     }
 
     /// Same as `try_coerce()`, but without side-effects.
@@ -1179,7 +1186,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .map(|ok| self.register_infer_ok_obligations(ok))?;
 
             // Reify both sides and return the reified fn pointer type.
-            let fn_ptr = self.tcx.mk_fn_ptr(sig);
+            let fn_ptr = Ty::new_fn_ptr(self.tcx, sig);
             let prev_adjustment = match prev_ty.kind() {
                 ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(a_sig.unsafety())),
                 ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer),
@@ -1430,7 +1437,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
             fcx,
             cause,
             None,
-            fcx.tcx.mk_unit(),
+            Ty::new_unit(fcx.tcx),
             Some(augment_error),
             label_unit_as_expected,
         )
@@ -1461,7 +1468,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
         // If we see any error types, just propagate that error
         // upwards.
         if let Err(guar) = (expression_ty, self.merged_ty()).error_reported() {
-            self.final_ty = Some(fcx.tcx.ty_error(guar));
+            self.final_ty = Some(Ty::new_error(fcx.tcx, guar));
             return;
         }
 
@@ -1649,7 +1656,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
 
                 let reported = err.emit_unless(unsized_return);
 
-                self.final_ty = Some(fcx.tcx.ty_error(reported));
+                self.final_ty = Some(Ty::new_error(fcx.tcx, reported));
             }
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 47f3c6b8407..cc8198aab25 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -1366,10 +1366,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // ```
                 let ref_ty = match mutability {
                     hir::Mutability::Mut => {
-                        self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, checked_ty)
+                        Ty::new_mut_ref(self.tcx,self.tcx.lifetimes.re_static, checked_ty)
                     }
                     hir::Mutability::Not => {
-                        self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, checked_ty)
+                        Ty::new_imm_ref(self.tcx,self.tcx.lifetimes.re_static, checked_ty)
                     }
                 };
                 if self.can_coerce(ref_ty, expected) {
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 265cacaf6c2..72b29f7b6e9 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -94,7 +94,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &adjustments[..] {
                     target.to_owned()
                 } else {
-                    self.tcx().ty_error(reported)
+                    Ty::new_error(self.tcx(), reported)
                 };
             }
 
@@ -321,7 +321,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     tcx.types.never
                 } else {
                     // There was an error; make type-check fail.
-                    tcx.ty_error_misc()
+                    Ty::new_misc_error(tcx)
                 }
             }
             ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
@@ -361,7 +361,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ExprKind::Field(base, field) => self.check_field(expr, &base, field, expected),
             ExprKind::Index(base, idx) => self.check_expr_index(base, idx, expr),
             ExprKind::Yield(value, ref src) => self.check_expr_yield(value, expr, src),
-            hir::ExprKind::Err(guar) => tcx.ty_error(guar),
+            hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar),
         }
     }
 
@@ -399,7 +399,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         {
                             err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
                         }
-                        oprnd_t = tcx.ty_error(err.emit());
+                        oprnd_t = Ty::new_error(tcx, err.emit());
                     }
                 }
                 hir::UnOp::Not => {
@@ -449,10 +449,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let tm = ty::TypeAndMut { ty, mutbl };
         match kind {
-            _ if tm.ty.references_error() => self.tcx.ty_error_misc(),
+            _ if tm.ty.references_error() => Ty::new_misc_error(self.tcx),
             hir::BorrowKind::Raw => {
                 self.check_named_place_expr(oprnd);
-                self.tcx.mk_ptr(tm)
+                Ty::new_ptr(self.tcx, tm)
             }
             hir::BorrowKind::Ref => {
                 // Note: at this point, we cannot say what the best lifetime
@@ -470,7 +470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // whose address was taken can actually be made to live as long
                 // as it needs to live.
                 let region = self.next_region_var(infer::AddrOfRegion(expr.span));
-                self.tcx.mk_ref(region, tm)
+                Ty::new_ref(self.tcx, region, tm)
             }
         }
     }
@@ -528,11 +528,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let e =
                     self.tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted");
                 self.set_tainted_by_errors(e);
-                tcx.ty_error(e)
+                Ty::new_error(tcx, e)
             }
             Res::Def(DefKind::Variant, _) => {
                 let e = report_unexpected_variant_res(tcx, res, qpath, expr.span, "E0533", "value");
-                tcx.ty_error(e)
+                Ty::new_error(tcx, e)
             }
             _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0,
         };
@@ -620,7 +620,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         Some(ctxt) => ctxt.coerce.as_ref().map(|coerce| coerce.expected_ty()),
                         None => {
                             // Avoid ICE when `break` is inside a closure (#65383).
-                            return tcx.ty_error_with_message(
+                            return Ty::new_error_with_message(
+                                tcx,
                                 expr.span,
                                 "break was outside loop, but no error was emitted",
                             );
@@ -631,7 +632,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // If the loop context is not a `loop { }`, then break with
                 // a value is illegal, and `opt_coerce_to` will be `None`.
                 // Just set expectation to error in that case.
-                let coerce_to = opt_coerce_to.unwrap_or_else(|| tcx.ty_error_misc());
+                let coerce_to = opt_coerce_to.unwrap_or_else(|| Ty::new_misc_error(tcx));
 
                 // Recurse without `enclosing_breakables` borrowed.
                 e_ty = self.check_expr_with_hint(e, coerce_to);
@@ -639,7 +640,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             } else {
                 // Otherwise, this is a break *without* a value. That's
                 // always legal, and is equivalent to `break ()`.
-                e_ty = tcx.mk_unit();
+                e_ty = Ty::new_unit(tcx);
                 cause = self.misc(expr.span);
             }
 
@@ -649,7 +650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
             let Some(ctxt) = enclosing_breakables.opt_find_breakable(target_id) else {
                 // Avoid ICE when `break` is inside a closure (#65383).
-                return tcx.ty_error_with_message(
+                return Ty::new_error_with_message(tcx,
                     expr.span,
                     "break was outside loop, but no error was emitted",
                 );
@@ -707,7 +708,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // this can only happen if the `break` was not
             // inside a loop at all, which is caught by the
             // loop-checking pass.
-            let err = self.tcx.ty_error_with_message(
+            let err = Ty::new_error_with_message(
+                self.tcx,
                 expr.span,
                 "break was outside loop, but no error was emitted",
             );
@@ -1072,7 +1074,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         let result_ty = coerce.complete(self);
-        if let Err(guar) = cond_ty.error_reported() { self.tcx.ty_error(guar) } else { result_ty }
+        if let Err(guar) = cond_ty.error_reported() {
+            Ty::new_error(self.tcx, guar)
+        } else {
+            result_ty
+        }
     }
 
     /// Type check assignment expression `expr` of form `lhs = rhs`.
@@ -1090,7 +1096,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // The expected type is `bool` but this will result in `()` so we can reasonably
             // say that the user intended to write `lhs == rhs` instead of `lhs = rhs`.
             // The likely cause of this is `if foo = bar { .. }`.
-            let actual_ty = self.tcx.mk_unit();
+            let actual_ty = Ty::new_unit(self.tcx);
             let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap();
             let lhs_ty = self.check_expr(&lhs);
             let rhs_ty = self.check_expr(&rhs);
@@ -1148,7 +1154,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // If the assignment expression itself is ill-formed, don't
             // bother emitting another error
             let reported = err.emit_unless(lhs_ty.references_error() || rhs_ty.references_error());
-            return self.tcx.ty_error(reported);
+            return Ty::new_error(self.tcx, reported);
         }
 
         let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
@@ -1195,9 +1201,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
 
         if let Err(guar) = (lhs_ty, rhs_ty).error_reported() {
-            self.tcx.ty_error(guar)
+            Ty::new_error(self.tcx, guar)
         } else {
-            self.tcx.mk_unit()
+            Ty::new_unit(self.tcx)
         }
     }
 
@@ -1252,7 +1258,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // [1]
             self.tcx.sess.delay_span_bug(body.span, "no coercion, but loop may not break");
         }
-        ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| self.tcx.mk_unit())
+        ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| Ty::new_unit(self.tcx))
     }
 
     /// Checks a method call.
@@ -1316,7 +1322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Eagerly check for some obvious errors.
         if let Err(guar) = (t_expr, t_cast).error_reported() {
-            self.tcx.ty_error(guar)
+            Ty::new_error(self.tcx, guar)
         } else {
             // Defer other checks until we're done type checking.
             let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
@@ -1337,7 +1343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     deferred_cast_checks.push(cast_check);
                     t_cast
                 }
-                Err(guar) => self.tcx.ty_error(guar),
+                Err(guar) => Ty::new_error(self.tcx, guar),
             }
         }
     }
@@ -1377,7 +1383,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
         let array_len = args.len() as u64;
         self.suggest_array_len(expr, array_len);
-        self.tcx.mk_array(element_ty, array_len)
+        Ty::new_array(self.tcx, element_ty, array_len)
     }
 
     fn suggest_array_len(&self, expr: &'tcx hir::Expr<'tcx>, array_len: u64) {
@@ -1465,18 +1471,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         if let Err(guar) = element_ty.error_reported() {
-            return tcx.ty_error(guar);
+            return Ty::new_error(tcx, guar);
         }
 
         self.check_repeat_element_needs_copy_bound(element, count, element_ty);
 
         self.register_wf_obligation(
-            tcx.mk_array_with_const_len(t, count).into(),
+            Ty::new_array_with_const_len(tcx, t, count).into(),
             expr.span,
             traits::WellFormed(None),
         );
 
-        tcx.mk_array_with_const_len(t, count)
+        Ty::new_array_with_const_len(tcx, t, count)
     }
 
     fn check_repeat_element_needs_copy_bound(
@@ -1539,9 +1545,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             _ => self.check_expr_with_expectation(&e, NoExpectation),
         });
-        let tuple = self.tcx.mk_tup_from_iter(elt_ts_iter);
+        let tuple = Ty::new_tup_from_iter(self.tcx, elt_ts_iter);
         if let Err(guar) = tuple.error_reported() {
-            self.tcx.ty_error(guar)
+            Ty::new_error(self.tcx, guar)
         } else {
             self.require_type_is_sized(tuple, expr.span, traits::TupleInitializerSized);
             tuple
@@ -1561,7 +1567,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Ok(data) => data,
             Err(guar) => {
                 self.check_struct_fields_on_error(fields, base_expr);
-                return self.tcx.ty_error(guar);
+                return Ty::new_error(self.tcx, guar);
             }
         };
 
@@ -1660,7 +1666,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     )
                 };
 
-                tcx.ty_error(guar)
+                Ty::new_error(tcx, guar)
             };
 
             // Make sure to give a type to the field even if there's
@@ -1772,7 +1778,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // `MyStruct<'a, _, F2, C>`, as opposed to just `_`...
                     // This is important to allow coercions to happen in
                     // `other_struct` itself. See `coerce-in-base-expr.rs`.
-                    let fresh_base_ty = self.tcx.mk_adt(*adt, fresh_substs);
+                    let fresh_base_ty = Ty::new_adt(self.tcx, *adt, fresh_substs);
                     self.check_expr_has_type_or_error(
                         base_expr,
                         self.resolve_vars_if_possible(fresh_base_ty),
@@ -2314,7 +2320,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 did,
                 expected.only_has_type(self),
             );
-            return self.tcx().ty_error(guar);
+            return Ty::new_error(self.tcx(), guar);
         }
 
         let guar = if field.name == kw::Empty {
@@ -2400,7 +2406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             err.emit()
         };
 
-        self.tcx().ty_error(guar)
+        Ty::new_error(self.tcx(), guar)
     }
 
     fn suggest_await_on_field_access(
@@ -2932,7 +2938,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
 
                     let reported = err.emit();
-                    self.tcx.ty_error(reported)
+                    Ty::new_error(self.tcx, reported)
                 }
             }
         }
@@ -3006,7 +3012,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let element_ty = ocx.normalize(
                 &cause,
                 self.param_env,
-                self.tcx.mk_projection(index_trait_output_def_id, impl_trait_ref.substs),
+                Ty::new_projection(self.tcx, index_trait_output_def_id, impl_trait_ref.substs),
             );
 
             let errors = ocx.select_where_possible();
@@ -3054,14 +3060,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // information. Hence, we check the source of the yield expression here and check its
             // value's type against `()` (this check should always hold).
             None if src.is_await() => {
-                self.check_expr_coercible_to_type(&value, self.tcx.mk_unit(), None);
-                self.tcx.mk_unit()
+                self.check_expr_coercible_to_type(&value, Ty::new_unit(self.tcx), None);
+                Ty::new_unit(self.tcx)
             }
             _ => {
                 self.tcx.sess.emit_err(YieldExprOutsideOfGenerator { span: expr.span });
                 // Avoid expressions without types during writeback (#78653).
                 self.check_expr(value);
-                self.tcx.mk_unit()
+                Ty::new_unit(self.tcx)
             }
         }
     }
@@ -3088,11 +3094,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let ty = self.structurally_resolve_type(expr.span, ty);
             match *ty.kind() {
                 ty::FnDef(..) => {
-                    let fnptr_ty = self.tcx.mk_fn_ptr(ty.fn_sig(self.tcx));
+                    let fnptr_ty = Ty::new_fn_ptr(self.tcx, ty.fn_sig(self.tcx));
                     self.demand_coerce(expr, ty, fnptr_ty, None, AllowTwoPhase::No);
                 }
                 ty::Ref(_, base_ty, mutbl) => {
-                    let ptr_ty = self.tcx.mk_ptr(ty::TypeAndMut { ty: base_ty, mutbl });
+                    let ptr_ty = Ty::new_ptr(self.tcx, ty::TypeAndMut { ty: base_ty, mutbl });
                     self.demand_coerce(expr, ty, ptr_ty, None, AllowTwoPhase::No);
                 }
                 _ => {}
@@ -3127,7 +3133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if asm.options.contains(ast::InlineAsmOptions::NORETURN) {
             self.tcx.types.never
         } else {
-            self.tcx.mk_unit()
+            Ty::new_unit(self.tcx)
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index b7ae621c685..a76db6e73a1 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -104,7 +104,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
         // type, `?T` is not considered unsolved, but `?I` is. The
         // same is true for float variables.)
         let fallback = match ty.kind() {
-            _ if let Some(e) = self.tainted_by_errors() => self.tcx.ty_error(e),
+            _ if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx,e),
             ty::Infer(ty::IntVar(_)) => self.tcx.types.i32,
             ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
             _ => match diverging_fallback.get(&ty) {
@@ -287,7 +287,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
         let mut diverging_fallback = FxHashMap::default();
         diverging_fallback.reserve(diverging_vids.len());
         for &diverging_vid in &diverging_vids {
-            let diverging_ty = self.tcx.mk_ty_var(diverging_vid);
+            let diverging_ty = Ty::new_var(self.tcx, diverging_vid);
             let root_vid = self.root_var(diverging_vid);
             let can_reach_non_diverging = coercion_graph
                 .depth_first_search(root_vid)
@@ -334,7 +334,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
                 diverging_fallback.insert(diverging_ty, self.tcx.types.unit);
             } else {
                 debug!("fallback to ! - all diverging: {:?}", diverging_vid);
-                diverging_fallback.insert(diverging_ty, self.tcx.mk_diverging_default());
+                diverging_fallback.insert(diverging_ty, Ty::new_diverging_default(self.tcx));
             }
         }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index adf1b8e351f..9a80a9c9303 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -453,7 +453,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
         match self.typeck_results.borrow().node_types().get(id) {
             Some(&t) => t,
-            None if let Some(e) = self.tainted_by_errors() => self.tcx.ty_error(e),
+            None if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx,e),
             None => {
                 bug!(
                     "no type for node {} in fcx {}",
@@ -467,7 +467,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn node_ty_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> {
         match self.typeck_results.borrow().node_types().get(id) {
             Some(&t) => Some(t),
-            None if let Some(e) = self.tainted_by_errors() => Some(self.tcx.ty_error(e)),
+            None if let Some(e) = self.tainted_by_errors() => Some(Ty::new_error(self.tcx,e)),
             None => None,
         }
     }
@@ -558,7 +558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.tcx,
                 self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
             );
-            let witness = self.tcx.mk_generator_witness_mir(expr_def_id.to_def_id(), substs);
+            let witness = Ty::new_generator_witness_mir(self.tcx, expr_def_id.to_def_id(), substs);
 
             // Unify `interior` with `witness` and collect all the resulting obligations.
             let span = self.tcx.hir().body(body_id).value.span;
@@ -703,7 +703,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     pub(in super::super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
-        let ty_error = self.tcx.ty_error_misc();
+        let ty_error = Ty::new_misc_error(self.tcx);
         vec![ty_error; len]
     }
 
@@ -1242,7 +1242,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         }
                     }
                     let reported = err.emit();
-                    return (tcx.ty_error(reported), res);
+                    return (Ty::new_error(tcx, reported), res);
                 }
             }
         } else {
@@ -1485,7 +1485,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Ok(normalized_ty) => normalized_ty,
                 Err(errors) => {
                     let guar = self.err_ctxt().report_fulfillment_errors(&errors);
-                    return self.tcx.ty_error(guar);
+                    return Ty::new_error(self.tcx,guar);
                 }
             }
         } else {
@@ -1512,7 +1512,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .emit_inference_failure_err(self.body_id, sp, ty.into(), E0282, true)
                     .emit()
             });
-            let err = self.tcx.ty_error(e);
+            let err = Ty::new_error(self.tcx, e);
             self.demand_suptype(sp, err, ty);
             err
         }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 7ce568ca48b..4bd4f2d7e9c 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -73,7 +73,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let ty = self.typeck_results.borrow().expr_ty_adjusted(expr);
                 let ty = self.resolve_vars_if_possible(ty);
                 if ty.has_non_region_infer() {
-                    self.tcx.ty_error_misc()
+                    Ty::new_misc_error(self.tcx)
                 } else {
                     self.tcx.erase_regions(ty)
                 }
@@ -101,7 +101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             let err_inputs = match tuple_arguments {
                 DontTupleArguments => err_inputs,
-                TupleArguments => vec![self.tcx.mk_tup(&err_inputs)],
+                TupleArguments => vec![Ty::new_tup(self.tcx, &err_inputs)],
             };
 
             self.check_argument_types(
@@ -114,7 +114,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 tuple_arguments,
                 method.ok().map(|method| method.def_id),
             );
-            return self.tcx.ty_error_misc();
+            return Ty::new_misc_error(self.tcx);
         }
 
         let method = method.unwrap();
@@ -424,7 +424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
                     }
                     ty::FnDef(..) => {
-                        let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx));
+                        let ptr_ty = Ty::new_fn_ptr(self.tcx, arg_ty.fn_sig(self.tcx));
                         let ptr_ty = self.resolve_vars_if_possible(ptr_ty);
                         variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string());
                     }
@@ -539,7 +539,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .typeck_results
                     .borrow()
                     .expr_ty_adjusted_opt(*expr)
-                    .unwrap_or_else(|| tcx.ty_error_misc());
+                    .unwrap_or_else(|| Ty::new_misc_error(tcx));
                 (self.resolve_vars_if_possible(ty), normalize_span(expr.span))
             })
             .collect();
@@ -648,7 +648,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
             {
                 // Wrap up the N provided arguments starting at this position in a tuple.
-                let provided_as_tuple = tcx.mk_tup_from_iter(
+                let provided_as_tuple = Ty::new_tup_from_iter(tcx,
                     provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()),
                 );
 
@@ -1309,14 +1309,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let tcx = self.tcx;
 
         match lit.node {
-            ast::LitKind::Str(..) => tcx.mk_static_str(),
-            ast::LitKind::ByteStr(ref v, _) => {
-                tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64))
-            }
+            ast::LitKind::Str(..) => Ty::new_static_str(tcx),
+            ast::LitKind::ByteStr(ref v, _) => Ty::new_imm_ref(
+                tcx,
+                tcx.lifetimes.re_static,
+                Ty::new_array(tcx, tcx.types.u8, v.len() as u64),
+            ),
             ast::LitKind::Byte(_) => tcx.types.u8,
             ast::LitKind::Char(_) => tcx.types.char,
-            ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(ty::int_ty(t)),
-            ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(ty::uint_ty(t)),
+            ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => Ty::new_int(tcx, ty::int_ty(t)),
+            ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => Ty::new_uint(tcx, ty::uint_ty(t)),
             ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
                 let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
                     ty::Int(_) | ty::Uint(_) => Some(ty),
@@ -1328,7 +1330,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 opt_ty.unwrap_or_else(|| self.next_int_var())
             }
             ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => {
-                tcx.mk_mach_float(ty::float_ty(t))
+                Ty::new_float(tcx, ty::float_ty(t))
             }
             ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => {
                 let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
@@ -1338,12 +1340,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 opt_ty.unwrap_or_else(|| self.next_float_var())
             }
             ast::LitKind::Bool(_) => tcx.types.bool,
-            ast::LitKind::CStr(_, _) => tcx.mk_imm_ref(
+            ast::LitKind::CStr(_, _) => Ty::new_imm_ref(
+                tcx,
                 tcx.lifetimes.re_static,
                 tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span)))
                     .skip_binder(),
             ),
-            ast::LitKind::Err => tcx.ty_error_misc(),
+            ast::LitKind::Err => Ty::new_misc_error(tcx),
         }
     }
 
@@ -1513,7 +1516,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             hir::StmtKind::Item(_) => {}
             hir::StmtKind::Expr(ref expr) => {
                 // Check with expected type of `()`.
-                self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| {
+                self.check_expr_has_type_or_error(&expr, Ty::new_unit(self.tcx), |err| {
                     if expr.can_have_side_effects() {
                         self.suggest_semicolon_at_end(expr.span, err);
                     }
@@ -1536,7 +1539,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) {
-        let unit = self.tcx.mk_unit();
+        let unit = Ty::new_unit(self.tcx);
         let ty = self.check_block_with_expected(blk, ExpectHasType(unit));
 
         // if the block produces a `!` value, that can always be
@@ -1649,7 +1652,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                         blk.span,
                                         blk.hir_id,
                                         expected_ty,
-                                        self.tcx.mk_unit(),
+                                        Ty::new_unit(self.tcx),
                                     );
                                 }
                                 if !self.consider_removing_semicolon(blk, expected_ty, err) {
@@ -1795,7 +1798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) {
         if let Err(guar) = ty.error_reported() {
             // Override the types everywhere with `err()` to avoid knock on errors.
-            let err = self.tcx.ty_error(guar);
+            let err = Ty::new_error(self.tcx, guar);
             self.write_ty(hir_id, err);
             self.write_ty(pat.hir_id, err);
             self.locals.borrow_mut().insert(hir_id, err);
@@ -1823,8 +1826,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let result = self
                     .astconv()
                     .associated_path_to_ty(hir_id, path_span, ty.raw, qself, segment, true);
-                let ty =
-                    result.map(|(ty, _, _)| ty).unwrap_or_else(|guar| self.tcx().ty_error(guar));
+                let ty = result
+                    .map(|(ty, _, _)| ty)
+                    .unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar));
                 let ty = self.handle_raw_ty(path_span, ty);
                 let result = result.map(|(_, kind, def_id)| (kind, def_id));
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index e035d233bf7..20b34df99b2 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -191,7 +191,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     pub fn next_root_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
-        self.tcx.mk_ty_var(self.next_ty_var_id_in_universe(origin, ty::UniverseIndex::ROOT))
+        Ty::new_var(self.tcx, self.next_ty_var_id_in_universe(origin, ty::UniverseIndex::ROOT))
     }
 }
 
@@ -295,7 +295,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
             trait_ref.substs,
         );
 
-        self.tcx().mk_projection(item_def_id, item_substs)
+        Ty::new_projection(self.tcx(), item_def_id, item_substs)
     }
 
     fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 3a4fe334f88..79a7c016185 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -426,7 +426,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // Given `Result<_, E>`, check our expected ty is `Result<_, &E>` for
             // `as_ref` and `as_deref` compatibility.
             let error_tys_equate_as_ref = error_tys.map_or(true, |(found, expected)| {
-                self.can_eq(self.param_env, self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, found), expected)
+                self.can_eq(self.param_env, Ty::new_imm_ref(self.tcx,self.tcx.lifetimes.re_erased, found), expected)
             });
             // FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`,
             // but those checks need to be a bit more delicate and the benefit is diminishing.
@@ -515,7 +515,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if self.tcx.hir().is_inside_const_context(hir_id) || !expected.is_box() || found.is_box() {
             return false;
         }
-        if self.can_coerce(self.tcx.mk_box(found), expected) {
+        if self.can_coerce(Ty::new_box(self.tcx, found), expected) {
             let suggest_boxing = match found.kind() {
                 ty::Tuple(tuple) if tuple.is_empty() => {
                     SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span }
@@ -595,9 +595,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() {
             return false;
         }
-        let box_found = self.tcx.mk_box(found);
-        let pin_box_found = self.tcx.mk_lang_item(box_found, LangItem::Pin).unwrap();
-        let pin_found = self.tcx.mk_lang_item(found, LangItem::Pin).unwrap();
+        let box_found = Ty::new_box(self.tcx, found);
+        let pin_box_found = Ty::new_lang_item(self.tcx, box_found, LangItem::Pin).unwrap();
+        let pin_found = Ty::new_lang_item(self.tcx, found, LangItem::Pin).unwrap();
         match expected.kind() {
             ty::Adt(def, _) if Some(def.did()) == pin_did => {
                 if self.can_coerce(pin_box_found, expected) {
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index fdbb153ec7d..86ea092bc40 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -312,7 +312,8 @@ pub fn resolve_interior<'a, 'tcx>(
     // Extract type components to build the witness type.
     let type_list = fcx.tcx.mk_type_list_from_iter(type_causes.iter().map(|cause| cause.ty));
     let bound_vars = fcx.tcx.mk_bound_variable_kinds(&bound_vars);
-    let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars));
+    let witness =
+        Ty::new_generator_witness(fcx.tcx, ty::Binder::bind_with_vars(type_list, bound_vars));
 
     drop(typeck_results);
     // Store the generator types and spans into the typeck results for this generator.
@@ -361,7 +362,8 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
                             let ty =
                                 self.interior_visitor.fcx.typeck_results.borrow().node_type(id);
                             let tcx = self.interior_visitor.fcx.tcx;
-                            let ty = tcx.mk_ref(
+                            let ty = Ty::new_ref(
+                                tcx,
                                 // Use `ReErased` as `resolve_interior` is going to replace all the
                                 // regions anyway.
                                 tcx.lifetimes.re_erased,
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 6f7288ed7e5..6f82ffcfe4a 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -154,7 +154,7 @@ fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tc
 fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
     let fallback = move || {
         let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id));
-        tcx.ty_error_with_message(span, "diagnostic only typeck table used")
+        Ty::new_error_with_message(tcx, span, "diagnostic only typeck table used")
     };
     typeck_with_fallback(tcx, def_id, fallback)
 }
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index 6c8589493cb..a1aa090841a 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -277,9 +277,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
             adjustment::Adjust::Deref(overloaded) => {
                 // Equivalent to *expr or something similar.
                 let base = if let Some(deref) = overloaded {
-                    let ref_ty = self
-                        .tcx()
-                        .mk_ref(deref.region, ty::TypeAndMut { ty: target, mutbl: deref.mutbl });
+                    let ref_ty = Ty::new_ref(
+                        self.tcx(),
+                        deref.region,
+                        ty::TypeAndMut { ty: target, mutbl: deref.mutbl },
+                    );
                     self.cat_rvalue(expr.hir_id, expr.span, ref_ty)
                 } else {
                     previous()?
@@ -489,7 +491,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         let ty::Ref(region, _, mutbl) = *base_ty.kind() else {
             span_bug!(expr.span, "cat_overloaded_place: base is not a reference");
         };
-        let ref_ty = self.tcx().mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl });
+        let ref_ty = Ty::new_ref(self.tcx(), region, ty::TypeAndMut { ty: place_ty, mutbl });
 
         let base = self.cat_rvalue(expr.hir_id, expr.span, ref_ty);
         self.cat_deref(expr, base)
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 966cd6a389e..55ad99e55af 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -143,7 +143,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         // a custom error in that case.
         if illegal_sized_bound.is_none() {
             self.add_obligations(
-                self.tcx.mk_fn_ptr(method_sig),
+                Ty::new_fn_ptr(self.tcx, method_sig),
                 all_substs,
                 method_predicates,
                 pick.item.def_id,
@@ -171,7 +171,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         // time writing the results into the various typeck results.
         let mut autoderef = self.autoderef(self.call_expr.span, unadjusted_self_ty);
         let Some((ty, n)) = autoderef.nth(pick.autoderefs) else {
-            return self.tcx.ty_error_with_message(
+            return Ty::new_error_with_message(self.tcx,
                 rustc_span::DUMMY_SP,
                 format!("failed autoderef {}", pick.autoderefs),
             );
@@ -187,7 +187,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                 // Type we're wrapping in a reference, used later for unsizing
                 let base_ty = target;
 
-                target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target });
+                target = Ty::new_ref(self.tcx, region, ty::TypeAndMut { mutbl, ty: target });
 
                 // Method call receivers are the primary use case
                 // for two-phase borrows.
@@ -200,16 +200,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
 
                 if unsize {
                     let unsized_ty = if let ty::Array(elem_ty, _) = base_ty.kind() {
-                        self.tcx.mk_slice(*elem_ty)
+                        Ty::new_slice(self.tcx, *elem_ty)
                     } else {
                         bug!(
                             "AutorefOrPtrAdjustment's unsize flag should only be set for array ty, found {}",
                             base_ty
                         )
                     };
-                    target = self
-                        .tcx
-                        .mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsized_ty });
+                    target = Ty::new_ref(
+                        self.tcx,
+                        region,
+                        ty::TypeAndMut { mutbl: mutbl.into(), ty: unsized_ty },
+                    );
                     adjustments
                         .push(Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target });
                 }
@@ -218,7 +220,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                 target = match target.kind() {
                     &ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => {
                         assert!(mutbl.is_mut());
-                        self.tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty })
+                        Ty::new_ptr(self.tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty })
                     }
                     other => panic!("Cannot adjust receiver type {:?} to const ptr", other),
                 };
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index ebd7b3123eb..e52cea1889f 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -205,9 +205,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if let Some(span) = result.illegal_sized_bound {
             let mut needs_mut = false;
             if let ty::Ref(region, t_type, mutability) = self_ty.kind() {
-                let trait_type = self
-                    .tcx
-                    .mk_ref(*region, ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() });
+                let trait_type = Ty::new_ref(
+                    self.tcx,
+                    *region,
+                    ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
+                );
                 // We probe again to see if there might be a borrow mutability discrepancy.
                 match self.lookup_probe(
                     segment.ident,
@@ -464,7 +466,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ));
 
         // Also add an obligation for the method type being well-formed.
-        let method_ty = tcx.mk_fn_ptr(ty::Binder::dummy(fn_sig));
+        let method_ty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(fn_sig));
         debug!(
             "lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
             method_ty, obligation
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 5e28ad5fd58..52e62837f35 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -465,7 +465,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     ty::Error(guar) => guar,
                     _ => bug!("unexpected bad final type in method autoderef"),
                 };
-                self.demand_eqtype(span, ty, self.tcx.ty_error(guar));
+                self.demand_eqtype(span, ty, Ty::new_error(self.tcx, guar));
                 return Err(MethodError::NoMatch(NoMatchData {
                     static_candidates: Vec::new(),
                     unsatisfied_predicates: Vec::new(),
@@ -551,7 +551,7 @@ fn method_autoderef_steps<'tcx>(
             steps.push(CandidateStep {
                 self_ty: infcx.make_query_response_ignoring_pending_obligations(
                     inference_vars,
-                    infcx.tcx.mk_slice(*elem_ty),
+                    Ty::new_slice(infcx.tcx, *elem_ty),
                 ),
                 autoderefs: dereferences,
                 // this could be from an unsafe deref if we had
@@ -1215,7 +1215,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         // In general, during probing we erase regions.
         let region = tcx.lifetimes.re_erased;
 
-        let autoref_ty = tcx.mk_ref(region, ty::TypeAndMut { ty: self_ty, mutbl });
+        let autoref_ty = Ty::new_ref(tcx, region, ty::TypeAndMut { ty: self_ty, mutbl });
         self.pick_method(autoref_ty, unstable_candidates).map(|r| {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
@@ -1245,7 +1245,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         };
 
         let const_self_ty = ty::TypeAndMut { ty, mutbl: hir::Mutability::Not };
-        let const_ptr_ty = self.tcx.mk_ptr(const_self_ty);
+        let const_ptr_ty = Ty::new_ptr(self.tcx, const_self_ty);
         self.pick_method(const_ptr_ty, unstable_candidates).map(|r| {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 67fb7c1d48c..5f924f30936 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -211,7 +211,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
                 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind() {
                     if needs_mut {
-                        let trait_type = self.tcx.mk_ref(
+                        let trait_type = Ty::new_ref(
+                            self.tcx,
                             *region,
                             ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
                         );
@@ -647,7 +648,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         let projection_ty = pred.skip_binder().projection_ty;
 
                         let substs_with_infer_self = tcx.mk_substs_from_iter(
-                            iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
+                            iter::once(Ty::new_var(tcx, ty::TyVid::from_u32(0)).into())
                                 .chain(projection_ty.substs.iter().skip(1)),
                         );
 
@@ -2408,8 +2409,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // just this list.
             for (rcvr_ty, post) in &[
                 (rcvr_ty, ""),
-                (self.tcx.mk_mut_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
-                (self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
+                (Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
+                (Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
             ] {
                 match self.lookup_probe_for_diagnostic(
                     item_name,
@@ -2444,10 +2445,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
 
                 for (rcvr_ty, pre) in &[
-                    (self.tcx.mk_lang_item(*rcvr_ty, LangItem::OwnedBox), "Box::new"),
-                    (self.tcx.mk_lang_item(*rcvr_ty, LangItem::Pin), "Pin::new"),
-                    (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Arc), "Arc::new"),
-                    (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Rc), "Rc::new"),
+                    (Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::OwnedBox), "Box::new"),
+                    (Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::Pin), "Pin::new"),
+                    (Ty::new_diagnostic_item(self.tcx, *rcvr_ty, sym::Arc), "Arc::new"),
+                    (Ty::new_diagnostic_item(self.tcx, *rcvr_ty, sym::Rc), "Rc::new"),
                 ] {
                     if let Some(new_rcvr_t) = *rcvr_ty
                         && let Ok(pick) = self.lookup_probe_for_diagnostic(
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 4f3d1d45679..1eae258c1b2 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -38,7 +38,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let ty =
             if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
                 self.enforce_builtin_binop_types(lhs.span, lhs_ty, rhs.span, rhs_ty, op);
-                self.tcx.mk_unit()
+                Ty::new_unit(self.tcx)
             } else {
                 return_ty
             };
@@ -297,7 +297,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             // error types are considered "builtin"
             Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => {
-                self.tcx.ty_error_misc()
+                Ty::new_misc_error(self.tcx)
             }
             Err(errors) => {
                 let (_, trait_def_id) =
@@ -568,7 +568,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
 
                 let reported = err.emit();
-                self.tcx.ty_error(reported)
+                Ty::new_error(self.tcx, reported)
             }
         };
 
@@ -752,7 +752,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                     err.emit()
                 });
-                self.tcx.ty_error(guar)
+                Ty::new_error(self.tcx, guar)
             }
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 96d03b47125..19f82fbd3bf 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -403,7 +403,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .borrow_mut()
                     .treat_byte_string_as_slice
                     .insert(lt.hir_id.local_id);
-                pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8));
+                pat_ty = Ty::new_imm_ref(tcx,tcx.lifetimes.re_static, Ty::new_slice(tcx,tcx.types.u8));
             }
         }
 
@@ -412,7 +412,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let expected = self.resolve_vars_if_possible(expected);
             pat_ty = match expected.kind() {
                 ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => expected,
-                ty::Str => tcx.mk_static_str(),
+                ty::Str => Ty::new_static_str(tcx,),
                 _ => pat_ty,
             };
         }
@@ -474,7 +474,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // There exists a side that didn't meet our criteria that the end-point
             // be of a numeric or char type, as checked in `calc_side` above.
             let guar = self.emit_err_pat_range(span, lhs, rhs);
-            return self.tcx.ty_error(guar);
+            return Ty::new_error(self.tcx, guar);
         }
 
         // Unify each side with `expected`.
@@ -494,7 +494,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         demand_eqtype(&mut rhs, lhs);
 
         if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
-            return self.tcx.ty_error_misc();
+            return Ty::new_misc_error(self.tcx);
         }
 
         // Find the unified type and check if it's of numeric or char type again.
@@ -510,7 +510,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 *fail = true;
             }
             let guar = self.emit_err_pat_range(span, lhs, rhs);
-            return self.tcx.ty_error(guar);
+            return Ty::new_error(self.tcx, guar);
         }
         ty
     }
@@ -848,7 +848,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) {
             Ok(data) => data,
             Err(guar) => {
-                let err = self.tcx.ty_error(guar);
+                let err = Ty::new_error(self.tcx, guar);
                 for field in fields {
                     let ti = ti;
                     self.check_pat(field.pat, err, def_bm, ti);
@@ -864,7 +864,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, def_bm, ti) {
             pat_ty
         } else {
-            self.tcx.ty_error_misc()
+            Ty::new_misc_error(self.tcx)
         }
     }
 
@@ -884,12 +884,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Res::Err => {
                 let e = tcx.sess.delay_span_bug(qpath.span(), "`Res::Err` but no error emitted");
                 self.set_tainted_by_errors(e);
-                return tcx.ty_error(e);
+                return Ty::new_error(tcx, e);
             }
             Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
                 let expected = "unit struct, unit variant or constant";
                 let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, "E0533", expected);
-                return tcx.ty_error(e);
+                return Ty::new_error(tcx, e);
             }
             Res::SelfCtor(..)
             | Res::Def(
@@ -1032,7 +1032,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let tcx = self.tcx;
         let on_error = |e| {
             for pat in subpats {
-                self.check_pat(pat, tcx.ty_error(e), def_bm, ti);
+                self.check_pat(pat, Ty::new_error(tcx, e), def_bm, ti);
             }
         };
         let report_unexpected_res = |res: Res| {
@@ -1049,7 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted");
             self.set_tainted_by_errors(e);
             on_error(e);
-            return tcx.ty_error(e);
+            return Ty::new_error(tcx, e);
         }
 
         // Type-check the path.
@@ -1057,7 +1057,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id);
         if !pat_ty.is_fn() {
             let e = report_unexpected_res(res);
-            return tcx.ty_error(e);
+            return Ty::new_error(tcx, e);
         }
 
         let variant = match res {
@@ -1065,11 +1065,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let e = tcx.sess.delay_span_bug(pat.span, "`Res::Err` but no error emitted");
                 self.set_tainted_by_errors(e);
                 on_error(e);
-                return tcx.ty_error(e);
+                return Ty::new_error(tcx, e);
             }
             Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => {
                 let e = report_unexpected_res(res);
-                return tcx.ty_error(e);
+                return Ty::new_error(tcx, e);
             }
             Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res),
             _ => bug!("unexpected pattern resolution: {:?}", res),
@@ -1112,7 +1112,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let e =
                 self.e0023(pat.span, res, qpath, subpats, &variant.fields.raw, expected, had_err);
             on_error(e);
-            return tcx.ty_error(e);
+            return Ty::new_error(tcx, e);
         }
         pat_ty
     }
@@ -1303,16 +1303,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             )
         });
         let element_tys = tcx.mk_type_list_from_iter(element_tys_iter);
-        let pat_ty = tcx.mk_tup(element_tys);
+        let pat_ty = Ty::new_tup(tcx, element_tys);
         if let Some(mut err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, ti) {
             let reported = err.emit();
             // Walk subpatterns with an expected type of `err` in this case to silence
             // further errors being emitted when using the bindings. #50333
-            let element_tys_iter = (0..max_len).map(|_| tcx.ty_error(reported));
+            let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported));
             for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
-                self.check_pat(elem, tcx.ty_error(reported), def_bm, ti);
+                self.check_pat(elem, Ty::new_error(tcx, reported), def_bm, ti);
             }
-            tcx.mk_tup_from_iter(element_tys_iter)
+            Ty::new_tup_from_iter(tcx, element_tys_iter)
         } else {
             for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
                 self.check_pat(elem, element_tys[i], def_bm, ti);
@@ -1357,7 +1357,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Occupied(occupied) => {
                     no_field_errors = false;
                     let guar = self.error_field_already_bound(span, field.ident, *occupied.get());
-                    tcx.ty_error(guar)
+                    Ty::new_error(tcx, guar)
                 }
                 Vacant(vacant) => {
                     vacant.insert(span);
@@ -1371,7 +1371,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         .unwrap_or_else(|| {
                             inexistent_fields.push(field);
                             no_field_errors = false;
-                            tcx.ty_error_misc()
+                            Ty::new_misc_error(tcx)
                         })
                 }
             };
@@ -1951,12 +1951,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     kind: TypeVariableOriginKind::TypeInference,
                     span: inner.span,
                 });
-                let box_ty = tcx.mk_box(inner_ty);
+                let box_ty = Ty::new_box(tcx, inner_ty);
                 self.demand_eqtype_pat(span, expected, box_ty, ti);
                 (box_ty, inner_ty)
             }
             Err(guar) => {
-                let err = tcx.ty_error(guar);
+                let err = Ty::new_error(tcx, guar);
                 (err, err)
             }
         };
@@ -2007,7 +2007,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             Err(guar) => {
-                let err = tcx.ty_error(guar);
+                let err = Ty::new_error(tcx, guar);
                 (err, err)
             }
         };
@@ -2019,7 +2019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn new_ref_ty(&self, span: Span, mutbl: hir::Mutability, ty: Ty<'tcx>) -> Ty<'tcx> {
         let region = self.next_region_var(infer::PatternRegion(span));
         let mt = ty::TypeAndMut { ty, mutbl };
-        self.tcx.mk_ref(region, mt)
+        Ty::new_ref(self.tcx, region, mt)
     }
 
     /// Type check a slice pattern.
@@ -2061,7 +2061,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .error_reported()
                     .err()
                     .unwrap_or_else(|| self.error_expected_array_or_slice(span, expected, ti));
-                let err = self.tcx.ty_error(guar);
+                let err = Ty::new_error(self.tcx, guar);
                 (err, Some(err), err)
             }
         };
@@ -2108,7 +2108,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             } else if let Some(pat_len) = len.checked_sub(min_len) {
                 // The variable-length pattern was there,
                 // so it has an array type with the remaining elements left as its size...
-                return (Some(self.tcx.mk_array(element_ty, pat_len)), arr_ty);
+                return (Some(Ty::new_array(self.tcx, element_ty, pat_len)), arr_ty);
             } else {
                 // ...however, in this case, there were no remaining elements.
                 // That is, the slice pattern requires more than the array type offers.
@@ -2117,7 +2117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         } else if slice.is_none() {
             // We have a pattern with a fixed length,
             // which we can use to infer the length of the array.
-            let updated_arr_ty = self.tcx.mk_array(element_ty, min_len);
+            let updated_arr_ty = Ty::new_array(self.tcx, element_ty, min_len);
             self.demand_eqtype(span, updated_arr_ty, arr_ty);
             return (None, updated_arr_ty);
         } else {
@@ -2128,7 +2128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         // If we get here, we must have emitted an error.
-        (Some(self.tcx.ty_error(guar)), arr_ty)
+        (Some(Ty::new_error(self.tcx, guar)), arr_ty)
     }
 
     fn error_scrutinee_inconsistent_length(
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index b8aaaebb85e..826cee3f982 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -90,7 +90,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
         }
         let reported = err.emit();
-        Some((self.tcx.ty_error(reported), self.tcx.ty_error(reported)))
+        Some((Ty::new_error(self.tcx, reported), Ty::new_error(self.tcx, reported)))
     }
 
     /// To type-check `base_expr[index_expr]`, we progressively autoderef
@@ -138,7 +138,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if unsize {
                 // We only unsize arrays here.
                 if let ty::Array(element_ty, _) = adjusted_ty.kind() {
-                    self_ty = self.tcx.mk_slice(*element_ty);
+                    self_ty = Ty::new_slice(self.tcx, *element_ty);
                 } else {
                     continue;
                 }
@@ -162,7 +162,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() {
                     adjustments.push(Adjustment {
                         kind: Adjust::Borrow(AutoBorrow::Ref(*region, AutoBorrowMutability::Not)),
-                        target: self.tcx.mk_ref(
+                        target: Ty::new_ref(
+                            self.tcx,
                             *region,
                             ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: adjusted_ty },
                         ),
@@ -427,9 +428,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         allow_two_phase_borrow: AllowTwoPhase::No,
                     };
                     adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(*region, mutbl));
-                    adjustment.target = self
-                        .tcx
-                        .mk_ref(*region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() });
+                    adjustment.target = Ty::new_ref(
+                        self.tcx,
+                        *region,
+                        ty::TypeAndMut { ty: source, mutbl: mutbl.into() },
+                    );
                 }
                 source = adjustment.target;
             }
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 9458099f56f..208c40a3932 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -300,7 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Build a tuple (U0..Un) of the final upvar types U0..Un
         // and unify the upvar tuple type in the closure with it:
-        let final_tupled_upvars_type = self.tcx.mk_tup(&final_upvar_tys);
+        let final_tupled_upvars_type = Ty::new_tup(self.tcx, &final_upvar_tys);
         self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type);
 
         let fake_reads = delegate
@@ -314,8 +314,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.typeck_results.borrow_mut().closure_size_eval.insert(
                 closure_def_id,
                 ClosureSizeProfileData {
-                    before_feature_tys: self.tcx.mk_tup(&before_feature_tys),
-                    after_feature_tys: self.tcx.mk_tup(&after_feature_tys),
+                    before_feature_tys: Ty::new_tup(self.tcx, &before_feature_tys),
+                    after_feature_tys: Ty::new_tup(self.tcx, &after_feature_tys),
                 },
             );
         }
@@ -1665,9 +1665,11 @@ fn apply_capture_kind_on_capture_ty<'tcx>(
 ) -> Ty<'tcx> {
     match capture_kind {
         ty::UpvarCapture::ByValue => ty,
-        ty::UpvarCapture::ByRef(kind) => {
-            tcx.mk_ref(region.unwrap(), ty::TypeAndMut { ty: ty, mutbl: kind.to_mutbl_lossy() })
-        }
+        ty::UpvarCapture::ByRef(kind) => Ty::new_ref(
+            tcx,
+            region.unwrap(),
+            ty::TypeAndMut { ty: ty, mutbl: kind.to_mutbl_lossy() },
+        ),
     }
 }
 
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 59b4c241fc1..01332483a06 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -232,7 +232,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                         // to access an nonexistent index. We assume that more relevant errors will
                         // already have been emitted, so we only gate on this with an ICE if no
                         // error has been emitted. (#64638)
-                        self.fcx.tcx.ty_error_with_message(
+                        Ty::new_error_with_message(
+                            self.fcx.tcx,
                             e.span,
                             format!("bad index {:?} for base: `{:?}`", index, base),
                         )
@@ -823,7 +824,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
                 debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
                 let e = self.report_error(t);
                 self.replaced_with_error = Some(e);
-                self.fcx.tcx.ty_error(e)
+                Ty::new_error(self.fcx.tcx, e)
             }
         }
     }
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 8ba0eb144b5..e57532e2de2 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -382,7 +382,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
                 // any equated inference vars correctly!
                 let root_vid = self.infcx.root_var(vid);
                 if root_vid != vid {
-                    t = self.infcx.tcx.mk_ty_var(root_vid);
+                    t = Ty::new_var(self.infcx.tcx, root_vid);
                     vid = root_vid;
                 }
 
@@ -785,7 +785,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
             self.fold_ty(bound_to)
         } else {
             let var = self.canonical_var(info, ty_var.into());
-            self.interner().mk_bound(self.binder_index, var.into())
+            Ty::new_bound(self.tcx, self.binder_index, var.into())
         }
     }
 
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 62f49741500..f765c41a367 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -26,7 +26,7 @@ use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVari
 use rustc_index::IndexVec;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::GenericArg;
-use rustc_middle::ty::{self, List, TyCtxt};
+use rustc_middle::ty::{self, List, Ty, TyCtxt};
 use rustc_span::source_map::Span;
 
 pub use rustc_middle::infer::canonical::*;
@@ -128,7 +128,7 @@ impl<'tcx> InferCtxt<'tcx> {
             CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, bound }) => {
                 let universe_mapped = universe_map(universe);
                 let placeholder_mapped = ty::PlaceholderType { universe: universe_mapped, bound };
-                self.tcx.mk_placeholder(placeholder_mapped).into()
+                Ty::new_placeholder(self.tcx, placeholder_mapped).into()
             }
 
             CanonicalVarKind::Region(ui) => self
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 32054e6d125..9c3ab04deae 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -520,7 +520,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 self.at(cause, param_env)
                     .eq(
                         DefineOpaqueTypes::Yes,
-                        self.tcx.mk_opaque(a.def_id.to_def_id(), a.substs),
+                        Ty::new_opaque(self.tcx, a.def_id.to_def_id(), a.substs),
                         b,
                     )?
                     .obligations,
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 0b93b6b9f27..a9cdb8c51cf 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -322,8 +322,8 @@ impl<'tcx> InferCtxt<'tcx> {
             .unify_var_value(vid, Some(val))
             .map_err(|e| int_unification_error(vid_is_expected, e))?;
         match val {
-            IntType(v) => Ok(self.tcx.mk_mach_int(v)),
-            UintType(v) => Ok(self.tcx.mk_mach_uint(v)),
+            IntType(v) => Ok(Ty::new_int(self.tcx, v)),
+            UintType(v) => Ok(Ty::new_uint(self.tcx, v)),
         }
     }
 
@@ -338,7 +338,7 @@ impl<'tcx> InferCtxt<'tcx> {
             .float_unification_table()
             .unify_var_value(vid, Some(ty::FloatVarValue(val)))
             .map_err(|e| float_unification_error(vid_is_expected, e))?;
-        Ok(self.tcx.mk_mach_float(val))
+        Ok(Ty::new_float(self.tcx, val))
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 15213c4b023..b826ced0453 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -315,7 +315,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
     let mut err = tcx.sess.create_err(errors::OpaqueCapturesLifetime {
         span,
-        opaque_ty: tcx.mk_opaque(opaque_ty_key.def_id.to_def_id(), opaque_ty_key.substs),
+        opaque_ty: Ty::new_opaque(tcx, opaque_ty_key.def_id.to_def_id(), opaque_ty_key.substs),
         opaque_ty_span: tcx.def_span(opaque_ty_key.def_id),
     });
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index aad9885827d..a9b485a6f7e 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -288,7 +288,7 @@ pub fn suggest_new_region_bound(
 
                 // Get the identity type for this RPIT
                 let did = item_id.owner_id.to_def_id();
-                let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did));
+                let ty = Ty::new_opaque(tcx, did, ty::InternalSubsts::identity_for_item(tcx, did));
 
                 if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg {
                     GenericBound::Outlives(Lifetime {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index ce70bcc5c85..12d38ced030 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -41,8 +41,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             // all of the region highlighting machinery only deals with those.
             let guar = self.emit_err(
                 var_origin.span(),
-                self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(expected)),
-                self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(found)),
+                Ty::new_fn_ptr(self.cx.tcx,ty::Binder::dummy(expected)),
+                Ty::new_fn_ptr(self.cx.tcx,ty::Binder::dummy(found)),
                 *trait_item_def_id,
             );
             return Some(guar);
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 07a9eff2dbe..e55e9e75fb6 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -11,7 +11,7 @@ use rustc_errors::{
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::{self, IsSuggestable, Region};
+use rustc_middle::ty::{self, IsSuggestable, Region, Ty};
 use rustc_span::symbol::kw;
 
 use super::ObligationCauseAsDiagArg;
@@ -304,7 +304,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         let trait_substs = trait_ref
             .subst_identity()
             // Replace the explicit self type with `Self` for better suggestion rendering
-            .with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper))
+            .with_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper))
             .substs;
         let trait_item_substs = ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id)
             .rebase_onto(self.tcx, impl_def_id, trait_substs);
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index 94cecdf0fb5..05769b7907a 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -188,7 +188,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
         match v {
             ty::TyVar(v) => {
                 let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known();
-                Some(self.freshen_ty(opt_ty, ty::TyVar(v), |n| self.infcx.tcx.mk_fresh_ty(n)))
+                Some(self.freshen_ty(opt_ty, ty::TyVar(v), |n| Ty::new_fresh(self.infcx.tcx, n)))
             }
 
             ty::IntVar(v) => Some(
@@ -200,7 +200,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
                         .probe_value(v)
                         .map(|v| v.to_type(self.infcx.tcx)),
                     ty::IntVar(v),
-                    |n| self.infcx.tcx.mk_fresh_int_ty(n),
+                    |n| Ty::new_fresh_int(self.infcx.tcx, n),
                 ),
             ),
 
@@ -213,7 +213,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
                         .probe_value(v)
                         .map(|v| v.to_type(self.infcx.tcx)),
                     ty::FloatVar(v),
-                    |n| self.infcx.tcx.mk_fresh_float_ty(n),
+                    |n| Ty::new_fresh_float(self.infcx.tcx, n),
                 ),
             ),
 
diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs
index 6d95055ff74..78025016757 100644
--- a/compiler/rustc_infer/src/infer/generalize.rs
+++ b/compiler/rustc_infer/src/infer/generalize.rs
@@ -277,7 +277,7 @@ where
                             let origin = *inner.type_variables().var_origin(vid);
                             let new_var_id =
                                 inner.type_variables().new_var(self.for_universe, origin);
-                            let u = self.tcx().mk_ty_var(new_var_id);
+                            let u = Ty::new_var(self.tcx(), new_var_id);
 
                             // Record that we replaced `vid` with `new_var_id` as part of a generalization
                             // operation. This is needed to detect cyclic types. To see why, see the
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index 31a6ac76aff..510b1797d3c 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -6,7 +6,7 @@ use super::{HigherRankedType, InferCtxt};
 use crate::infer::CombinedSnapshot;
 use rustc_middle::ty::fold::FnMutDelegate;
 use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::{self, Binder, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Binder, Ty, TyCtxt, TypeFoldable};
 
 impl<'a, 'tcx> CombineFields<'a, 'tcx> {
     /// Checks whether `for<..> sub <: for<..> sup` holds.
@@ -88,10 +88,10 @@ impl<'tcx> InferCtxt<'tcx> {
                 )
             },
             types: &mut |bound_ty: ty::BoundTy| {
-                self.tcx.mk_placeholder(ty::PlaceholderType {
-                    universe: next_universe,
-                    bound: bound_ty,
-                })
+                Ty::new_placeholder(
+                    self.tcx,
+                    ty::PlaceholderType { universe: next_universe, bound: bound_ty },
+                )
             },
             consts: &mut |bound_var: ty::BoundVar, ty| {
                 ty::Const::new_placeholder(
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 53d691eca24..fca32b73d1d 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -725,19 +725,19 @@ impl<'tcx> InferCtxt<'tcx> {
             .type_variables()
             .unsolved_variables()
             .into_iter()
-            .map(|t| self.tcx.mk_ty_var(t))
+            .map(|t| Ty::new_var(self.tcx, t))
             .collect();
         vars.extend(
             (0..inner.int_unification_table().len())
                 .map(|i| ty::IntVid { index: i as u32 })
                 .filter(|&vid| inner.int_unification_table().probe_value(vid).is_none())
-                .map(|v| self.tcx.mk_int_var(v)),
+                .map(|v| Ty::new_int_var(self.tcx, v)),
         );
         vars.extend(
             (0..inner.float_unification_table().len())
                 .map(|i| ty::FloatVid { index: i as u32 })
                 .filter(|&vid| inner.float_unification_table().probe_value(vid).is_none())
-                .map(|v| self.tcx.mk_float_var(v)),
+                .map(|v| Ty::new_float_var(self.tcx, v)),
         );
         vars
     }
@@ -978,7 +978,7 @@ impl<'tcx> InferCtxt<'tcx> {
     }
 
     pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
-        self.tcx.mk_ty_var(self.next_ty_var_id(origin))
+        Ty::new_var(self.tcx, self.next_ty_var_id(origin))
     }
 
     pub fn next_ty_var_id_in_universe(
@@ -995,7 +995,7 @@ impl<'tcx> InferCtxt<'tcx> {
         universe: ty::UniverseIndex,
     ) -> Ty<'tcx> {
         let vid = self.next_ty_var_id_in_universe(origin, universe);
-        self.tcx.mk_ty_var(vid)
+        Ty::new_var(self.tcx, vid)
     }
 
     pub fn next_const_var(&self, ty: Ty<'tcx>, origin: ConstVariableOrigin) -> ty::Const<'tcx> {
@@ -1028,7 +1028,7 @@ impl<'tcx> InferCtxt<'tcx> {
     }
 
     pub fn next_int_var(&self) -> Ty<'tcx> {
-        self.tcx.mk_int_var(self.next_int_var_id())
+        Ty::new_int_var(self.tcx, self.next_int_var_id())
     }
 
     fn next_float_var_id(&self) -> FloatVid {
@@ -1036,7 +1036,7 @@ impl<'tcx> InferCtxt<'tcx> {
     }
 
     pub fn next_float_var(&self) -> Ty<'tcx> {
-        self.tcx.mk_float_var(self.next_float_var_id())
+        Ty::new_float_var(self.tcx, self.next_float_var_id())
     }
 
     /// Creates a fresh region variable with the next available index.
@@ -1116,7 +1116,7 @@ impl<'tcx> InferCtxt<'tcx> {
                     },
                 );
 
-                self.tcx.mk_ty_var(ty_var_id).into()
+                Ty::new_var(self.tcx, ty_var_id).into()
             }
             GenericParamDefKind::Const { .. } => {
                 let origin = ConstVariableOrigin {
@@ -1265,7 +1265,7 @@ impl<'tcx> InferCtxt<'tcx> {
         if let Some(value) = inner.int_unification_table().probe_value(vid) {
             value.to_type(self.tcx)
         } else {
-            self.tcx.mk_int_var(inner.int_unification_table().find(vid))
+            Ty::new_int_var(self.tcx, inner.int_unification_table().find(vid))
         }
     }
 
@@ -1276,7 +1276,7 @@ impl<'tcx> InferCtxt<'tcx> {
         if let Some(value) = inner.float_unification_table().probe_value(vid) {
             value.to_type(self.tcx)
         } else {
-            self.tcx.mk_float_var(inner.float_unification_table().find(vid))
+            Ty::new_float_var(self.tcx, inner.float_unification_table().find(vid))
         }
     }
 
@@ -1945,13 +1945,16 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>(
                     self.idx += 1;
                     idx
                 };
-                self.tcx.mk_placeholder(ty::PlaceholderType {
-                    universe: ty::UniverseIndex::ROOT,
-                    bound: ty::BoundTy {
-                        var: ty::BoundVar::from_u32(idx),
-                        kind: ty::BoundTyKind::Anon,
+                Ty::new_placeholder(
+                    self.tcx,
+                    ty::PlaceholderType {
+                        universe: ty::UniverseIndex::ROOT,
+                        bound: ty::BoundTy {
+                            var: ty::BoundVar::from_u32(idx),
+                            kind: ty::BoundTyKind::Anon,
+                        },
                     },
-                })
+                )
             } else {
                 t.super_fold_with(self)
             }
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index d9f9d2aabdb..27e1ed56f31 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -118,7 +118,7 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
 
             (&ty::Error(e), _) | (_, &ty::Error(e)) => {
                 infcx.set_tainted_by_errors(e);
-                Ok(self.tcx().ty_error(e))
+                Ok(Ty::new_error(self.tcx(), e))
             }
 
             (
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 3aeed93baf2..074ff7ec97f 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -3,7 +3,7 @@ use smallvec::smallvec;
 use crate::infer::outlives::components::{push_outlives_components, Component};
 use crate::traits::{self, Obligation, PredicateObligation};
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
-use rustc_middle::ty::{self, ToPredicate, TyCtxt};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
@@ -344,7 +344,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
                             }
 
                             Component::Param(p) => {
-                                let ty = tcx.mk_ty_param(p.index, p.name);
+                                let ty = Ty::new_param(tcx, p.index, p.name);
                                 Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, r_min)))
                             }
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index c24760263bf..b821933e908 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -674,21 +674,21 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
                     return;
                 }
                 let def = cx.tcx.adt_def(item.owner_id);
-                (def, cx.tcx.mk_adt(def, ty::List::empty()))
+                (def, Ty::new_adt(cx.tcx, def, ty::List::empty()))
             }
             hir::ItemKind::Union(_, ref ast_generics) => {
                 if !ast_generics.params.is_empty() {
                     return;
                 }
                 let def = cx.tcx.adt_def(item.owner_id);
-                (def, cx.tcx.mk_adt(def, ty::List::empty()))
+                (def, Ty::new_adt(cx.tcx, def, ty::List::empty()))
             }
             hir::ItemKind::Enum(_, ref ast_generics) => {
                 if !ast_generics.params.is_empty() {
                     return;
                 }
                 let def = cx.tcx.adt_def(item.owner_id);
-                (def, cx.tcx.mk_adt(def, ty::List::empty()))
+                (def, Ty::new_adt(cx.tcx, def, ty::List::empty()))
             }
             _ => return,
         };
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 13164b0b339..3761754f3ae 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -1345,7 +1345,7 @@ impl<'tcx> LateContext<'tcx> {
         tcx.associated_items(trait_id)
             .find_by_name_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id)
             .and_then(|assoc| {
-                let proj = tcx.mk_projection(assoc.def_id, [self_ty]);
+                let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
                 tcx.try_normalize_erasing_regions(self.param_env, proj).ok()
             })
     }
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 63a56806a45..09a1651c2f5 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
             }
 
             let proj_ty =
-                cx.tcx.mk_projection(proj.projection_ty.def_id, proj.projection_ty.substs);
+                Ty::new_projection(cx.tcx, proj.projection_ty.def_id, proj.projection_ty.substs);
             // For every instance of the projection type in the bounds,
             // replace them with the term we're assigning to the associated
             // type in our opaque type.
@@ -144,7 +144,8 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
                         OPAQUE_HIDDEN_INFERRED_BOUND,
                         pred_span,
                         OpaqueHiddenInferredBoundLint {
-                            ty: cx.tcx.mk_opaque(
+                            ty: Ty::new_opaque(
+                                cx.tcx,
                                 def_id,
                                 ty::InternalSubsts::identity_for_item(cx.tcx, def_id),
                             ),
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 0ae0306b5ac..2509d493a4c 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -862,12 +862,12 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
             };
             return get_nullable_type(cx, inner_field_ty);
         }
-        ty::Int(ty) => tcx.mk_mach_int(ty),
-        ty::Uint(ty) => tcx.mk_mach_uint(ty),
-        ty::RawPtr(ty_mut) => tcx.mk_ptr(ty_mut),
+        ty::Int(ty) => Ty::new_int(tcx, ty),
+        ty::Uint(ty) => Ty::new_uint(tcx, ty),
+        ty::RawPtr(ty_mut) => Ty::new_ptr(tcx, ty_mut),
         // As these types are always non-null, the nullable equivalent of
         // Option<T> of these types are their raw pointer counterparts.
-        ty::Ref(_region, ty, mutbl) => tcx.mk_ptr(ty::TypeAndMut { ty, mutbl }),
+        ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty::TypeAndMut { ty, mutbl }),
         ty::FnPtr(..) => {
             // There is no nullable equivalent for Rust's function pointers -- you
             // must use an Option<fn(..) -> _> to represent it.
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index d9287c05a47..d5e8330b3f6 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -433,7 +433,8 @@ impl<'tcx> CanonicalVarValues<'tcx> {
                 |(i, info)| -> ty::GenericArg<'tcx> {
                     match info.kind {
                         CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
-                            tcx.mk_bound(ty::INNERMOST, ty::BoundVar::from_usize(i).into()).into()
+                            Ty::new_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i).into())
+                                .into()
                         }
                         CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
                             let br = ty::BoundRegion {
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index 991b9f01985..85fb9214d9d 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -90,15 +90,15 @@ impl<'tcx> UnifyValue for UnifiedRegion<'tcx> {
 impl ToType for ty::IntVarValue {
     fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match *self {
-            ty::IntType(i) => tcx.mk_mach_int(i),
-            ty::UintType(i) => tcx.mk_mach_uint(i),
+            ty::IntType(i) => Ty::new_int(tcx, i),
+            ty::UintType(i) => Ty::new_uint(tcx, i),
         }
     }
 }
 
 impl ToType for ty::FloatVarValue {
     fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
-        tcx.mk_mach_float(self.0)
+        Ty::new_float(tcx, self.0)
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 7642350e00c..efb01b0faba 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -1913,7 +1913,7 @@ impl<'tcx> Operand<'tcx> {
         substs: impl IntoIterator<Item = GenericArg<'tcx>>,
         span: Span,
     ) -> Self {
-        let ty = tcx.mk_fn_def(def_id, substs);
+        let ty = Ty::new_fn_def(tcx, def_id, substs);
         Operand::Constant(Box::new(Constant {
             span,
             user_ty: None,
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 65dff193c80..8618a531527 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -95,11 +95,13 @@ impl<'tcx> PlaceTy<'tcx> {
             ProjectionElem::Subslice { from, to, from_end } => {
                 PlaceTy::from_ty(match self.ty.kind() {
                     ty::Slice(..) => self.ty,
-                    ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64),
+                    ty::Array(inner, _) if !from_end => {
+                        Ty::new_array(tcx, *inner, (to - from) as u64)
+                    }
                     ty::Array(inner, size) if from_end => {
                         let size = size.eval_target_usize(tcx, param_env);
                         let len = size - from - to;
-                        tcx.mk_array(*inner, len)
+                        Ty::new_array(tcx, *inner, len)
                     }
                     _ => bug!("cannot subslice non-array type: `{:?}`", self),
                 })
@@ -162,16 +164,16 @@ impl<'tcx> Rvalue<'tcx> {
         match *self {
             Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
             Rvalue::Repeat(ref operand, count) => {
-                tcx.mk_array_with_const_len(operand.ty(local_decls, tcx), count)
+                Ty::new_array_with_const_len(tcx, operand.ty(local_decls, tcx), count)
             }
             Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did),
             Rvalue::Ref(reg, bk, ref place) => {
                 let place_ty = place.ty(local_decls, tcx).ty;
-                tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() })
+                Ty::new_ref(tcx, reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() })
             }
             Rvalue::AddressOf(mutability, ref place) => {
                 let place_ty = place.ty(local_decls, tcx).ty;
-                tcx.mk_ptr(ty::TypeAndMut { ty: place_ty, mutbl: mutability })
+                Ty::new_ptr(tcx, ty::TypeAndMut { ty: place_ty, mutbl: mutability })
             }
             Rvalue::Len(..) => tcx.types.usize,
             Rvalue::Cast(.., ty) => ty,
@@ -184,7 +186,7 @@ impl<'tcx> Rvalue<'tcx> {
                 let lhs_ty = lhs.ty(local_decls, tcx);
                 let rhs_ty = rhs.ty(local_decls, tcx);
                 let ty = op.ty(tcx, lhs_ty, rhs_ty);
-                tcx.mk_tup(&[ty, tcx.types.bool])
+                Ty::new_tup(tcx, &[ty, tcx.types.bool])
             }
             Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx),
             Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
@@ -192,17 +194,17 @@ impl<'tcx> Rvalue<'tcx> {
                 tcx.types.usize
             }
             Rvalue::Aggregate(ref ak, ref ops) => match **ak {
-                AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64),
+                AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64),
                 AggregateKind::Tuple => {
-                    tcx.mk_tup_from_iter(ops.iter().map(|op| op.ty(local_decls, tcx)))
+                    Ty::new_tup_from_iter(tcx, ops.iter().map(|op| op.ty(local_decls, tcx)))
                 }
                 AggregateKind::Adt(did, _, substs, _, _) => tcx.type_of(did).subst(tcx, substs),
-                AggregateKind::Closure(did, substs) => tcx.mk_closure(did, substs),
+                AggregateKind::Closure(did, substs) => Ty::new_closure(tcx, did, substs),
                 AggregateKind::Generator(did, substs, movability) => {
-                    tcx.mk_generator(did, substs, movability)
+                    Ty::new_generator(tcx, did, substs, movability)
                 }
             },
-            Rvalue::ShallowInitBox(_, ty) => tcx.mk_box(ty),
+            Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty),
             Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty,
         }
     }
diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs
index cbc68fde9d9..09517200b0d 100644
--- a/compiler/rustc_middle/src/ty/_match.rs
+++ b/compiler/rustc_middle/src/ty/_match.rs
@@ -81,7 +81,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
                 Err(TypeError::Sorts(relate::expected_found(self, a, b)))
             }
 
-            (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(self.tcx().ty_error(guar)),
+            (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.tcx(), guar)),
 
             _ => relate::structurally_relate_tys(self, a, b),
         }
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index cd0f7e8daf1..a4893684bc8 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -132,7 +132,7 @@ impl<'tcx> OverloadedDeref<'tcx> {
             .find(|m| m.kind == ty::AssocKind::Fn)
             .unwrap()
             .def_id;
-        tcx.mk_fn_def(method_def_id, [source])
+        Ty::new_fn_def(tcx, method_def_id, [source])
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 78943cb0ddb..1cbfe99f87f 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -125,7 +125,7 @@ impl<'tcx> Const<'tcx> {
         Const::new(tcx, ty::ConstKind::Error(e), ty)
     }
 
-    /// Like [TyCtxt::ty_error] but for constants.
+    /// Like [Ty::new_error] but for constants.
     #[track_caller]
     pub fn new_misc_error(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
         Const::new_error_with_message(
@@ -136,7 +136,7 @@ impl<'tcx> Const<'tcx> {
         )
     }
 
-    /// Like [TyCtxt::ty_error_with_message] but for constants.
+    /// Like [Ty::new_error_with_message] but for constants.
     #[track_caller]
     pub fn new_error_with_message<S: Into<MultiSpan>>(
         tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 9bc5baad68c..035e978f64c 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -25,10 +25,10 @@ use crate::traits::solve::{
     ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData,
 };
 use crate::ty::{
-    self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, FloatTy, FloatVar,
-    FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst,
-    ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind,
-    ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
+    self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, GenericParamDefKind,
+    ImplPolarity, InferTy, List, ParamConst, ParamTy, PolyExistentialPredicate, PolyFnSig,
+    Predicate, PredicateKind, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind,
+    TyVid, TypeAndMut, Visibility,
 };
 use crate::ty::{GenericArg, InternalSubsts, SubstsRef};
 use rustc_ast::{self as ast, attr};
@@ -70,10 +70,9 @@ use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}
 use rustc_target::spec::abi;
 use rustc_type_ir::sty::TyKind::*;
 use rustc_type_ir::WithCachedTypeInfo;
-use rustc_type_ir::{CollectAndApply, DynKind, Interner, TypeFlags};
+use rustc_type_ir::{CollectAndApply, Interner, TypeFlags};
 
 use std::any::Any;
-use std::assert_matches::debug_assert_matches;
 use std::borrow::Borrow;
 use std::cmp::Ordering;
 use std::fmt;
@@ -727,30 +726,6 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    /// Constructs a `TyKind::Error` type with current `ErrorGuaranteed`
-    #[track_caller]
-    pub fn ty_error(self, reported: ErrorGuaranteed) -> Ty<'tcx> {
-        self.mk_ty_from_kind(Error(reported))
-    }
-
-    /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
-    #[track_caller]
-    pub fn ty_error_misc(self) -> Ty<'tcx> {
-        self.ty_error_with_message(DUMMY_SP, "TyKind::Error constructed but no error reported")
-    }
-
-    /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to
-    /// ensure it gets used.
-    #[track_caller]
-    pub fn ty_error_with_message<S: Into<MultiSpan>>(
-        self,
-        span: S,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> Ty<'tcx> {
-        let reported = self.sess.delay_span_bug(span, msg);
-        self.mk_ty_from_kind(Error(reported))
-    }
-
     pub fn consider_optimizing<T: Fn() -> String>(self, msg: T) -> bool {
         self.sess.consider_optimizing(|| self.crate_name(LOCAL_CRATE), msg)
     }
@@ -1144,7 +1119,8 @@ impl<'tcx> TyCtxt<'tcx> {
 
     /// Returns `&'static core::panic::Location<'static>`.
     pub fn caller_location_ty(self) -> Ty<'tcx> {
-        self.mk_imm_ref(
+        Ty::new_imm_ref(
+            self,
             self.lifetimes.re_static,
             self.type_of(self.require_lang_item(LangItem::PanicLocation, None))
                 .subst(self, self.mk_substs(&[self.lifetimes.re_static.into()])),
@@ -1542,7 +1518,10 @@ impl<'tcx> TyCtxt<'tcx> {
     /// unsafe.
     pub fn safe_to_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
         assert_eq!(sig.unsafety(), hir::Unsafety::Normal);
-        self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig }))
+        Ty::new_fn_ptr(
+            self,
+            sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig }),
+        )
     }
 
     /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name`
@@ -1616,18 +1595,6 @@ impl<'tcx> TyCtxt<'tcx> {
         })
     }
 
-    // Avoid this in favour of more specific `mk_*` methods, where possible.
-    #[allow(rustc::usage_of_ty_tykind)]
-    #[inline]
-    pub fn mk_ty_from_kind(self, st: TyKind<'tcx>) -> Ty<'tcx> {
-        self.interners.intern_ty(
-            st,
-            self.sess,
-            // This is only used to create a stable hashing context.
-            &self.untracked,
-        )
-    }
-
     #[inline]
     pub fn mk_predicate(self, binder: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> {
         self.interners.intern_predicate(
@@ -1647,174 +1614,6 @@ impl<'tcx> TyCtxt<'tcx> {
         if pred.kind() != binder { self.mk_predicate(binder) } else { pred }
     }
 
-    pub fn mk_mach_int(self, tm: IntTy) -> Ty<'tcx> {
-        match tm {
-            IntTy::Isize => self.types.isize,
-            IntTy::I8 => self.types.i8,
-            IntTy::I16 => self.types.i16,
-            IntTy::I32 => self.types.i32,
-            IntTy::I64 => self.types.i64,
-            IntTy::I128 => self.types.i128,
-        }
-    }
-
-    pub fn mk_mach_uint(self, tm: UintTy) -> Ty<'tcx> {
-        match tm {
-            UintTy::Usize => self.types.usize,
-            UintTy::U8 => self.types.u8,
-            UintTy::U16 => self.types.u16,
-            UintTy::U32 => self.types.u32,
-            UintTy::U64 => self.types.u64,
-            UintTy::U128 => self.types.u128,
-        }
-    }
-
-    pub fn mk_mach_float(self, tm: FloatTy) -> Ty<'tcx> {
-        match tm {
-            FloatTy::F32 => self.types.f32,
-            FloatTy::F64 => self.types.f64,
-        }
-    }
-
-    #[inline]
-    pub fn mk_static_str(self) -> Ty<'tcx> {
-        self.mk_imm_ref(self.lifetimes.re_static, self.types.str_)
-    }
-
-    #[inline]
-    pub fn mk_adt(self, def: AdtDef<'tcx>, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
-        // Take a copy of substs so that we own the vectors inside.
-        self.mk_ty_from_kind(Adt(def, substs))
-    }
-
-    #[inline]
-    pub fn mk_foreign(self, def_id: DefId) -> Ty<'tcx> {
-        self.mk_ty_from_kind(Foreign(def_id))
-    }
-
-    fn mk_generic_adt(self, wrapper_def_id: DefId, ty_param: Ty<'tcx>) -> Ty<'tcx> {
-        let adt_def = self.adt_def(wrapper_def_id);
-        let substs =
-            InternalSubsts::for_item(self, wrapper_def_id, |param, substs| match param.kind {
-                GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => bug!(),
-                GenericParamDefKind::Type { has_default, .. } => {
-                    if param.index == 0 {
-                        ty_param.into()
-                    } else {
-                        assert!(has_default);
-                        self.type_of(param.def_id).subst(self, substs).into()
-                    }
-                }
-            });
-        self.mk_ty_from_kind(Adt(adt_def, substs))
-    }
-
-    #[inline]
-    pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let def_id = self.require_lang_item(LangItem::OwnedBox, None);
-        self.mk_generic_adt(def_id, ty)
-    }
-
-    #[inline]
-    pub fn mk_lang_item(self, ty: Ty<'tcx>, item: LangItem) -> Option<Ty<'tcx>> {
-        let def_id = self.lang_items().get(item)?;
-        Some(self.mk_generic_adt(def_id, ty))
-    }
-
-    #[inline]
-    pub fn mk_diagnostic_item(self, ty: Ty<'tcx>, name: Symbol) -> Option<Ty<'tcx>> {
-        let def_id = self.get_diagnostic_item(name)?;
-        Some(self.mk_generic_adt(def_id, ty))
-    }
-
-    #[inline]
-    pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let def_id = self.require_lang_item(LangItem::MaybeUninit, None);
-        self.mk_generic_adt(def_id, ty)
-    }
-
-    #[inline]
-    pub fn mk_ptr(self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
-        self.mk_ty_from_kind(RawPtr(tm))
-    }
-
-    #[inline]
-    pub fn mk_ref(self, r: Region<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
-        self.mk_ty_from_kind(Ref(r, tm.ty, tm.mutbl))
-    }
-
-    #[inline]
-    pub fn mk_mut_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.mk_ref(r, TypeAndMut { ty, mutbl: hir::Mutability::Mut })
-    }
-
-    #[inline]
-    pub fn mk_imm_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.mk_ref(r, TypeAndMut { ty, mutbl: hir::Mutability::Not })
-    }
-
-    #[inline]
-    pub fn mk_mut_ptr(self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.mk_ptr(TypeAndMut { ty, mutbl: hir::Mutability::Mut })
-    }
-
-    #[inline]
-    pub fn mk_imm_ptr(self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.mk_ptr(TypeAndMut { ty, mutbl: hir::Mutability::Not })
-    }
-
-    #[inline]
-    pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
-        self.mk_ty_from_kind(Array(ty, ty::Const::from_target_usize(self, n)))
-    }
-
-    #[inline]
-    pub fn mk_array_with_const_len(self, ty: Ty<'tcx>, ct: Const<'tcx>) -> Ty<'tcx> {
-        self.mk_ty_from_kind(Array(ty, ct))
-    }
-
-    #[inline]
-    pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.mk_ty_from_kind(Slice(ty))
-    }
-
-    #[inline]
-    pub fn mk_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> {
-        if ts.is_empty() {
-            self.types.unit
-        } else {
-            self.mk_ty_from_kind(Tuple(self.mk_type_list(&ts)))
-        }
-    }
-
-    pub fn mk_tup_from_iter<I, T>(self, iter: I) -> T::Output
-    where
-        I: Iterator<Item = T>,
-        T: CollectAndApply<Ty<'tcx>, Ty<'tcx>>,
-    {
-        T::collect_and_apply(iter, |ts| self.mk_tup(ts))
-    }
-
-    #[inline]
-    pub fn mk_unit(self) -> Ty<'tcx> {
-        self.types.unit
-    }
-
-    #[inline]
-    pub fn mk_diverging_default(self) -> Ty<'tcx> {
-        if self.features().never_type_fallback { self.types.never } else { self.types.unit }
-    }
-
-    #[inline]
-    pub fn mk_fn_def(
-        self,
-        def_id: DefId,
-        substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
-    ) -> Ty<'tcx> {
-        let substs = self.check_and_mk_substs(def_id, substs);
-        self.mk_ty_from_kind(FnDef(def_id, substs))
-    }
-
     #[inline(always)]
     pub(crate) fn check_and_mk_substs(
         self,
@@ -1846,131 +1645,20 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     #[inline]
-    pub fn mk_fn_ptr(self, fty: PolyFnSig<'tcx>) -> Ty<'tcx> {
-        self.mk_ty_from_kind(FnPtr(fty))
-    }
-
-    #[inline]
-    pub fn mk_dynamic(
-        self,
-        obj: &'tcx List<PolyExistentialPredicate<'tcx>>,
-        reg: ty::Region<'tcx>,
-        repr: DynKind,
-    ) -> Ty<'tcx> {
-        self.mk_ty_from_kind(Dynamic(obj, reg, repr))
-    }
-
-    #[inline]
-    pub fn mk_projection(
-        self,
-        item_def_id: DefId,
-        substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
-    ) -> Ty<'tcx> {
-        self.mk_alias(ty::Projection, self.mk_alias_ty(item_def_id, substs))
-    }
-
-    #[inline]
-    pub fn mk_closure(self, def_id: DefId, closure_substs: SubstsRef<'tcx>) -> Ty<'tcx> {
-        debug_assert_eq!(
-            closure_substs.len(),
-            self.generics_of(self.typeck_root_def_id(def_id)).count() + 3,
-            "closure constructed with incorrect substitutions"
-        );
-        self.mk_ty_from_kind(Closure(def_id, closure_substs))
-    }
-
-    #[inline]
-    pub fn mk_generator(
-        self,
-        def_id: DefId,
-        generator_substs: SubstsRef<'tcx>,
-        movability: hir::Movability,
-    ) -> Ty<'tcx> {
-        debug_assert_eq!(
-            generator_substs.len(),
-            self.generics_of(self.typeck_root_def_id(def_id)).count() + 5,
-            "generator constructed with incorrect number of substitutions"
-        );
-        self.mk_ty_from_kind(Generator(def_id, generator_substs, movability))
-    }
-
-    #[inline]
-    pub fn mk_generator_witness(self, types: ty::Binder<'tcx, &'tcx List<Ty<'tcx>>>) -> Ty<'tcx> {
-        self.mk_ty_from_kind(GeneratorWitness(types))
-    }
-
-    /// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes.
-    pub fn mk_task_context(self) -> Ty<'tcx> {
-        let context_did = self.require_lang_item(LangItem::Context, None);
-        let context_adt_ref = self.adt_def(context_did);
-        let context_substs = self.mk_substs(&[self.lifetimes.re_erased.into()]);
-        let context_ty = self.mk_adt(context_adt_ref, context_substs);
-        self.mk_mut_ref(self.lifetimes.re_erased, context_ty)
-    }
-
-    #[inline]
-    pub fn mk_generator_witness_mir(self, id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
-        self.mk_ty_from_kind(GeneratorWitnessMIR(id, substs))
-    }
-
-    #[inline]
     pub fn mk_ct_from_kind(self, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
         self.intern_const(ty::ConstData { kind, ty })
     }
 
+    // Avoid this in favour of more specific `Ty::new_*` methods, where possible.
+    #[allow(rustc::usage_of_ty_tykind)]
     #[inline]
-    pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> {
-        // Use a pre-interned one when possible.
-        self.types
-            .ty_vars
-            .get(v.as_usize())
-            .copied()
-            .unwrap_or_else(|| self.mk_ty_from_kind(Infer(TyVar(v))))
-    }
-
-    #[inline]
-    pub fn mk_int_var(self, v: IntVid) -> Ty<'tcx> {
-        self.mk_ty_from_kind(Infer(IntVar(v)))
-    }
-
-    #[inline]
-    pub fn mk_float_var(self, v: FloatVid) -> Ty<'tcx> {
-        self.mk_ty_from_kind(Infer(FloatVar(v)))
-    }
-
-    #[inline]
-    pub fn mk_fresh_ty(self, n: u32) -> Ty<'tcx> {
-        // Use a pre-interned one when possible.
-        self.types
-            .fresh_tys
-            .get(n as usize)
-            .copied()
-            .unwrap_or_else(|| self.mk_ty_from_kind(Infer(ty::FreshTy(n))))
-    }
-
-    #[inline]
-    pub fn mk_fresh_int_ty(self, n: u32) -> Ty<'tcx> {
-        // Use a pre-interned one when possible.
-        self.types
-            .fresh_int_tys
-            .get(n as usize)
-            .copied()
-            .unwrap_or_else(|| self.mk_ty_from_kind(Infer(ty::FreshIntTy(n))))
-    }
-
-    #[inline]
-    pub fn mk_fresh_float_ty(self, n: u32) -> Ty<'tcx> {
-        // Use a pre-interned one when possible.
-        self.types
-            .fresh_float_tys
-            .get(n as usize)
-            .copied()
-            .unwrap_or_else(|| self.mk_ty_from_kind(Infer(ty::FreshFloatTy(n))))
-    }
-
-    #[inline]
-    pub fn mk_ty_param(self, index: u32, name: Symbol) -> Ty<'tcx> {
-        self.mk_ty_from_kind(Param(ParamTy { index, name }))
+    pub fn mk_ty_from_kind(self, st: TyKind<'tcx>) -> Ty<'tcx> {
+        self.interners.intern_ty(
+            st,
+            self.sess,
+            // This is only used to create a stable hashing context.
+            &self.untracked,
+        )
     }
 
     pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
@@ -1978,7 +1666,7 @@ impl<'tcx> TyCtxt<'tcx> {
             GenericParamDefKind::Lifetime => {
                 ty::Region::new_early_bound(self, param.to_early_bound_region_data()).into()
             }
-            GenericParamDefKind::Type { .. } => self.mk_ty_param(param.index, param.name).into(),
+            GenericParamDefKind::Type { .. } => Ty::new_param(self, param.index, param.name).into(),
             GenericParamDefKind::Const { .. } => ty::Const::new_param(
                 self,
                 ParamConst { index: param.index, name: param.name },
@@ -1990,33 +1678,6 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    #[inline]
-    pub fn mk_bound(self, index: ty::DebruijnIndex, bound_ty: ty::BoundTy) -> Ty<'tcx> {
-        self.mk_ty_from_kind(Bound(index, bound_ty))
-    }
-
-    #[inline]
-    pub fn mk_placeholder(self, placeholder: ty::PlaceholderType) -> Ty<'tcx> {
-        self.mk_ty_from_kind(Placeholder(placeholder))
-    }
-
-    #[inline]
-    pub fn mk_alias(self, kind: ty::AliasKind, alias_ty: ty::AliasTy<'tcx>) -> Ty<'tcx> {
-        debug_assert_matches!(
-            (kind, self.def_kind(alias_ty.def_id)),
-            (ty::Opaque, DefKind::OpaqueTy)
-                | (ty::Projection | ty::Inherent, DefKind::AssocTy)
-                | (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder)
-                | (ty::Weak, DefKind::TyAlias)
-        );
-        self.mk_ty_from_kind(Alias(kind, alias_ty))
-    }
-
-    #[inline]
-    pub fn mk_opaque(self, def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
-        self.mk_alias(ty::Opaque, self.mk_alias_ty(def_id, substs))
-    }
-
     pub fn mk_place_field(self, place: Place<'tcx>, f: FieldIdx, ty: Ty<'tcx>) -> Place<'tcx> {
         self.mk_place_elem(place, PlaceElem::Field(f, ty))
     }
@@ -2367,21 +2028,6 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 }
 
-impl<'tcx> TyCtxtAt<'tcx> {
-    /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
-    #[track_caller]
-    pub fn ty_error_misc(self) -> Ty<'tcx> {
-        self.tcx.ty_error_with_message(self.span, "TyKind::Error constructed but no error reported")
-    }
-
-    /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to
-    /// ensure it gets used.
-    #[track_caller]
-    pub fn ty_error_with_message(self, msg: impl Into<DiagnosticMessage>) -> Ty<'tcx> {
-        self.tcx.ty_error_with_message(self.span, msg)
-    }
-}
-
 /// Parameter attributes that can only be determined by examining the body of a function instead
 /// of just its signature.
 ///
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index d89baa9c88d..a0b17c374e4 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -559,7 +559,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
             Infer(InferTy::TyVar(_)) if self.infer_suggestable => t,
 
             FnDef(def_id, substs) => {
-                self.tcx.mk_fn_ptr(self.tcx.fn_sig(def_id).subst(self.tcx, substs))
+                Ty::new_fn_ptr(self.tcx, self.tcx.fn_sig(def_id).subst(self.tcx, substs))
             }
 
             // FIXME(compiler-errors): We could replace these with infer, I guess.
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 410b7fe6173..77cf6bee79d 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -348,7 +348,11 @@ impl<'tcx> TyCtxt<'tcx> {
                     )
                 },
                 types: &mut |t: ty::BoundTy| {
-                    self.mk_bound(ty::INNERMOST, ty::BoundTy { var: shift_bv(t.var), kind: t.kind })
+                    Ty::new_bound(
+                        self,
+                        ty::INNERMOST,
+                        ty::BoundTy { var: shift_bv(t.var), kind: t.kind },
+                    )
                 },
                 consts: &mut |c, ty: Ty<'tcx>| {
                     ty::Const::new_bound(self, ty::INNERMOST, shift_bv(c), ty)
@@ -393,7 +397,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 let kind = entry
                     .or_insert_with(|| ty::BoundVariableKind::Ty(ty::BoundTyKind::Anon))
                     .expect_ty();
-                self.tcx.mk_bound(ty::INNERMOST, BoundTy { var, kind })
+                Ty::new_bound(self.tcx, ty::INNERMOST, BoundTy { var, kind })
             }
             fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> {
                 let entry = self.map.entry(bv);
@@ -462,7 +466,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Shifter<'tcx> {
         match *ty.kind() {
             ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
                 let debruijn = debruijn.shifted_in(self.amount);
-                self.tcx.mk_bound(debruijn, bound_ty)
+                Ty::new_bound(self.tcx, debruijn, bound_ty)
             }
 
             _ if ty.has_vars_bound_at_or_above(self.current_index) => ty.super_fold_with(self),
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 452bbf11263..6c7125c4cb7 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::Span;
 
-use super::{Clause, EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, TyCtxt};
+use super::{Clause, EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Ty, TyCtxt};
 
 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum GenericParamDefKind {
@@ -101,7 +101,7 @@ impl GenericParamDef {
     ) -> ty::GenericArg<'tcx> {
         match &self.kind {
             ty::GenericParamDefKind::Lifetime => ty::Region::new_error_misc(tcx).into(),
-            ty::GenericParamDefKind::Type { .. } => tcx.ty_error_misc().into(),
+            ty::GenericParamDefKind::Type { .. } => Ty::new_misc_error(tcx).into(),
             ty::GenericParamDefKind::Const { .. } => ty::Const::new_misc_error(
                 tcx,
                 tcx.type_of(self.def_id).subst(tcx, preceding_substs),
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 96750e4ab85..ae57e954ff4 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -552,7 +552,7 @@ impl<'tcx> Instance<'tcx> {
             tcx.codegen_fn_attrs(closure_did).flags.contains(CodegenFnAttrFlags::TRACK_CALLER);
         let def = ty::InstanceDef::ClosureOnceShim { call_once, track_caller };
 
-        let self_ty = tcx.mk_closure(closure_did, substs);
+        let self_ty = Ty::new_closure(tcx, closure_did, substs);
 
         let sig = substs.as_closure().sig();
         let sig =
@@ -680,7 +680,7 @@ fn polymorphize<'tcx>(
                     if substs == polymorphized_substs {
                         ty
                     } else {
-                        self.tcx.mk_closure(def_id, polymorphized_substs)
+                        Ty::new_closure(self.tcx, def_id, polymorphized_substs)
                     }
                 }
                 ty::Generator(def_id, substs, movability) => {
@@ -689,7 +689,7 @@ fn polymorphize<'tcx>(
                     if substs == polymorphized_substs {
                         ty
                     } else {
-                        self.tcx.mk_generator(def_id, polymorphized_substs, movability)
+                        Ty::new_generator(self.tcx, def_id, polymorphized_substs, movability)
                     }
                 }
                 _ => ty.super_fold_with(self),
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 7a628e6b89b..0fe801ad2ed 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -133,7 +133,7 @@ impl PrimitiveExt for Primitive {
             F32 => tcx.types.f32,
             F64 => tcx.types.f64,
             // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
-            Pointer(_) => tcx.mk_mut_ptr(tcx.mk_unit()),
+            Pointer(_) => Ty::new_mut_ptr(tcx, Ty::new_unit(tcx)),
         }
     }
 
@@ -810,11 +810,11 @@ where
                     // (which may have no non-DST form), and will work as long
                     // as the `Abi` or `FieldsShape` is checked by users.
                     if i == 0 {
-                        let nil = tcx.mk_unit();
+                        let nil = Ty::new_unit(tcx);
                         let unit_ptr_ty = if this.ty.is_unsafe_ptr() {
-                            tcx.mk_mut_ptr(nil)
+                            Ty::new_mut_ptr(tcx, nil)
                         } else {
-                            tcx.mk_mut_ref(tcx.lifetimes.re_static, nil)
+                            Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, nil)
                         };
 
                         // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing
@@ -827,7 +827,11 @@ where
                     }
 
                     let mk_dyn_vtable = || {
-                        tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3))
+                        Ty::new_imm_ref(
+                            tcx,
+                            tcx.lifetimes.re_static,
+                            Ty::new_array(tcx, tcx.types.usize, 3),
+                        )
                         /* FIXME: use actual fn pointers
                         Warning: naively computing the number of entries in the
                         vtable by counting the methods on the trait + methods on
@@ -836,9 +840,9 @@ where
                         Increase this counter if you tried to implement this but
                         failed to do it without duplicating a lot of code from
                         other places in the compiler: 2
-                        tcx.mk_tup(&[
-                            tcx.mk_array(tcx.types.usize, 3),
-                            tcx.mk_array(Option<fn()>),
+                        Ty::new_tup(tcx,&[
+                            Ty::new_array(tcx,tcx.types.usize, 3),
+                            Ty::new_array(tcx,Option<fn()>),
                         ])
                         */
                     };
@@ -850,7 +854,7 @@ where
                     {
                         let metadata = tcx.normalize_erasing_regions(
                             cx.param_env(),
-                            tcx.mk_projection(metadata_def_id, [pointee]),
+                            Ty::new_projection(tcx,metadata_def_id, [pointee]),
                         );
 
                         // Map `Metadata = DynMetadata<dyn Trait>` back to a vtable, since it
@@ -925,15 +929,14 @@ where
 
                 ty::Dynamic(_, _, ty::DynStar) => {
                     if i == 0 {
-                        TyMaybeWithLayout::Ty(tcx.mk_mut_ptr(tcx.types.unit))
+                        TyMaybeWithLayout::Ty(Ty::new_mut_ptr(tcx, tcx.types.unit))
                     } else if i == 1 {
                         // FIXME(dyn-star) same FIXME as above applies here too
-                        TyMaybeWithLayout::Ty(
-                            tcx.mk_imm_ref(
-                                tcx.lifetimes.re_static,
-                                tcx.mk_array(tcx.types.usize, 3),
-                            ),
-                        )
+                        TyMaybeWithLayout::Ty(Ty::new_imm_ref(
+                            tcx,
+                            tcx.lifetimes.re_static,
+                            Ty::new_array(tcx, tcx.types.usize, 3),
+                        ))
                     } else {
                         bug!("no field {i} on dyn*")
                     }
@@ -978,10 +981,8 @@ where
                 })
             }
             ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
-                tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| PointeeInfo {
-                    size: layout.size,
-                    align: layout.align.abi,
-                    safe: None,
+                tcx.layout_of(param_env.and(Ty::new_fn_ptr(tcx, fn_sig))).ok().map(|layout| {
+                    PointeeInfo { size: layout.size, align: layout.align.abi, safe: None }
                 })
             }
             ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs
index f944b9ae2d8..b10921eff08 100644
--- a/compiler/rustc_middle/src/ty/opaque_types.rs
+++ b/compiler/rustc_middle/src/ty/opaque_types.rs
@@ -150,17 +150,17 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
         match *ty.kind() {
             ty::Closure(def_id, substs) => {
                 let substs = self.fold_closure_substs(def_id, substs);
-                self.tcx.mk_closure(def_id, substs)
+                Ty::new_closure(self.tcx, def_id, substs)
             }
 
             ty::Generator(def_id, substs, movability) => {
                 let substs = self.fold_closure_substs(def_id, substs);
-                self.tcx.mk_generator(def_id, substs, movability)
+                Ty::new_generator(self.tcx, def_id, substs, movability)
             }
 
             ty::GeneratorWitnessMIR(def_id, substs) => {
                 let substs = self.fold_closure_substs(def_id, substs);
-                self.tcx.mk_generator_witness_mir(def_id, substs)
+                Ty::new_generator_witness_mir(self.tcx, def_id, substs)
             }
 
             ty::Param(param) => {
@@ -186,7 +186,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
                                 .emit();
                         }
 
-                        self.interner().ty_error_misc()
+                        Ty::new_misc_error(self.tcx)
                     }
                 }
             }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index fc27f98a96f..96cf36eb996 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1228,7 +1228,7 @@ pub trait PrettyPrinter<'tcx>:
                 // in order to place the projections inside the `<...>`.
                 if !resugared {
                     // Use a type that can't appear in defaults of type parameters.
-                    let dummy_cx = cx.tcx().mk_fresh_ty(0);
+                    let dummy_cx = Ty::new_fresh(cx.tcx(), 0);
                     let principal = principal.with_self_ty(cx.tcx(), dummy_cx);
 
                     let args = cx
@@ -2736,7 +2736,7 @@ define_print_and_forward_display! {
 
     ty::ExistentialTraitRef<'tcx> {
         // Use a type that can't appear in defaults of type parameters.
-        let dummy_self = cx.tcx().mk_fresh_ty(0);
+        let dummy_self = Ty::new_fresh(cx.tcx(),0);
         let trait_ref = self.with_self_ty(cx.tcx(), dummy_self);
         p!(print(trait_ref.print_only_trait_path()))
     }
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index d1f22de10c5..5741832c980 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -408,7 +408,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             bug!("bound types encountered in structurally_relate_tys")
         }
 
-        (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(tcx.ty_error(guar)),
+        (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(tcx, guar)),
 
         (&ty::Never, _)
         | (&ty::Char, _)
@@ -428,10 +428,10 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
 
         (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs)) if a_def == b_def => {
             let substs = relation.relate_item_substs(a_def.did(), a_substs, b_substs)?;
-            Ok(tcx.mk_adt(a_def, substs))
+            Ok(Ty::new_adt(tcx, a_def, substs))
         }
 
-        (&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(tcx.mk_foreign(a_id)),
+        (&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(tcx, a_id)),
 
         (&ty::Dynamic(a_obj, a_region, a_repr), &ty::Dynamic(b_obj, b_region, b_repr))
             if a_repr == b_repr =>
@@ -439,7 +439,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
                 relation.relate(a_region, b_region)
             })?;
-            Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound, a_repr))
+            Ok(Ty::new_dynamic(tcx, relation.relate(a_obj, b_obj)?, region_bound, a_repr))
         }
 
         (&ty::Generator(a_id, a_substs, movability), &ty::Generator(b_id, b_substs, _))
@@ -449,7 +449,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             // the (anonymous) type of the same generator expression. So
             // all of their regions should be equated.
             let substs = relation.relate(a_substs, b_substs)?;
-            Ok(tcx.mk_generator(a_id, substs, movability))
+            Ok(Ty::new_generator(tcx, a_id, substs, movability))
         }
 
         (&ty::GeneratorWitness(a_types), &ty::GeneratorWitness(b_types)) => {
@@ -459,7 +459,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             let b_types = b_types.map_bound(GeneratorWitness);
             // Then remove the GeneratorWitness for the result
             let types = relation.relate(a_types, b_types)?.map_bound(|witness| witness.0);
-            Ok(tcx.mk_generator_witness(types))
+            Ok(Ty::new_generator_witness(tcx, types))
         }
 
         (&ty::GeneratorWitnessMIR(a_id, a_substs), &ty::GeneratorWitnessMIR(b_id, b_substs))
@@ -469,7 +469,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             // the (anonymous) type of the same generator expression. So
             // all of their regions should be equated.
             let substs = relation.relate(a_substs, b_substs)?;
-            Ok(tcx.mk_generator_witness_mir(a_id, substs))
+            Ok(Ty::new_generator_witness_mir(tcx, a_id, substs))
         }
 
         (&ty::Closure(a_id, a_substs), &ty::Closure(b_id, b_substs)) if a_id == b_id => {
@@ -477,12 +477,12 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             // the (anonymous) type of the same closure expression. So
             // all of their regions should be equated.
             let substs = relation.relate(a_substs, b_substs)?;
-            Ok(tcx.mk_closure(a_id, &substs))
+            Ok(Ty::new_closure(tcx, a_id, &substs))
         }
 
         (&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => {
             let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;
-            Ok(tcx.mk_ptr(mt))
+            Ok(Ty::new_ptr(tcx, mt))
         }
 
         (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => {
@@ -490,13 +490,13 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl };
             let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl };
             let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;
-            Ok(tcx.mk_ref(r, mt))
+            Ok(Ty::new_ref(tcx, r, mt))
         }
 
         (&ty::Array(a_t, sz_a), &ty::Array(b_t, sz_b)) => {
             let t = relation.relate(a_t, b_t)?;
             match relation.relate(sz_a, sz_b) {
-                Ok(sz) => Ok(tcx.mk_array_with_const_len(t, sz)),
+                Ok(sz) => Ok(Ty::new_array_with_const_len(tcx, t, sz)),
                 Err(err) => {
                     // Check whether the lengths are both concrete/known values,
                     // but are unequal, for better diagnostics.
@@ -519,12 +519,15 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
 
         (&ty::Slice(a_t), &ty::Slice(b_t)) => {
             let t = relation.relate(a_t, b_t)?;
-            Ok(tcx.mk_slice(t))
+            Ok(Ty::new_slice(tcx, t))
         }
 
         (&ty::Tuple(as_), &ty::Tuple(bs)) => {
             if as_.len() == bs.len() {
-                Ok(tcx.mk_tup_from_iter(iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)))?)
+                Ok(Ty::new_tup_from_iter(
+                    tcx,
+                    iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)),
+                )?)
             } else if !(as_.is_empty() || bs.is_empty()) {
                 Err(TypeError::TupleSize(expected_found(relation, as_.len(), bs.len())))
             } else {
@@ -536,12 +539,12 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             if a_def_id == b_def_id =>
         {
             let substs = relation.relate_item_substs(a_def_id, a_substs, b_substs)?;
-            Ok(tcx.mk_fn_def(a_def_id, substs))
+            Ok(Ty::new_fn_def(tcx, a_def_id, substs))
         }
 
         (&ty::FnPtr(a_fty), &ty::FnPtr(b_fty)) => {
             let fty = relation.relate(a_fty, b_fty)?;
-            Ok(tcx.mk_fn_ptr(fty))
+            Ok(Ty::new_fn_ptr(tcx, fty))
         }
 
         // The substs of opaque types may not all be invariant, so we have
@@ -559,7 +562,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
                 b_substs,
                 false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
             )?;
-            Ok(tcx.mk_opaque(a_def_id, substs))
+            Ok(Ty::new_opaque(tcx, a_def_id, substs))
         }
 
         // Alias tend to mostly already be handled downstream due to normalization.
@@ -569,7 +572,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             if a_kind == b_kind {
                 let alias_ty = relation.relate(a_data, b_data)?;
                 // assert_eq!(a_kind, b_kind);
-                Ok(tcx.mk_alias(a_kind, alias_ty))
+                Ok(Ty::new_alias(tcx, a_kind, alias_ty))
             } else {
                 Err(TypeError::Sorts(expected_found(relation, a, b)))
             }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 9046570699e..94746fbdc19 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -15,6 +15,7 @@ use hir::def::DefKind;
 use polonius_engine::Atom;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::intern::Interned;
+use rustc_error_messages::DiagnosticMessage;
 use rustc_errors::{DiagnosticArgValue, ErrorGuaranteed, IntoDiagnosticArg, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -25,6 +26,7 @@ use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
 use rustc_target::spec::abi::{self, Abi};
+use std::assert_matches::debug_assert_matches;
 use std::borrow::Cow;
 use std::cmp::Ordering;
 use std::fmt;
@@ -33,9 +35,11 @@ use std::ops::{ControlFlow, Deref, Range};
 use ty::util::IntTypeExt;
 
 use rustc_type_ir::sty::TyKind::*;
-use rustc_type_ir::ConstKind as IrConstKind;
-use rustc_type_ir::RegionKind as IrRegionKind;
 use rustc_type_ir::TyKind as IrTyKind;
+use rustc_type_ir::{CollectAndApply, ConstKind as IrConstKind};
+use rustc_type_ir::{DynKind, RegionKind as IrRegionKind};
+
+use super::GenericParamDefKind;
 
 // Re-export the `TyKind` from `rustc_type_ir` here for convenience
 #[rustc_diagnostic_item = "TyKind"]
@@ -1241,7 +1245,7 @@ impl<'tcx> AliasTy<'tcx> {
     }
 
     pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
-        tcx.mk_alias(self.kind(tcx), self)
+        Ty::new_alias(tcx, self.kind(tcx), self)
     }
 }
 
@@ -1432,7 +1436,7 @@ impl<'tcx> ParamTy {
 
     #[inline]
     pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
-        tcx.mk_ty_param(self.index, self.name)
+        Ty::new_param(tcx, self.index, self.name)
     }
 
     pub fn span_from_generics(&self, tcx: TyCtxt<'tcx>, item_with_generics: DefId) -> Span {
@@ -1873,6 +1877,390 @@ impl<'tcx> Region<'tcx> {
     }
 }
 
+/// Constructors for `Ty`
+impl<'tcx> Ty<'tcx> {
+    // Avoid this in favour of more specific `new_*` methods, where possible.
+    #[allow(rustc::usage_of_ty_tykind)]
+    #[inline]
+    pub fn new(tcx: TyCtxt<'tcx>, st: TyKind<'tcx>) -> Ty<'tcx> {
+        tcx.mk_ty_from_kind(st)
+    }
+
+    #[inline]
+    pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferTy) -> Ty<'tcx> {
+        Ty::new(tcx, TyKind::Infer(infer))
+    }
+
+    #[inline]
+    pub fn new_var(tcx: TyCtxt<'tcx>, v: ty::TyVid) -> Ty<'tcx> {
+        // Use a pre-interned one when possible.
+        tcx.types
+            .ty_vars
+            .get(v.as_usize())
+            .copied()
+            .unwrap_or_else(|| Ty::new(tcx, Infer(TyVar(v))))
+    }
+
+    #[inline]
+    pub fn new_int_var(tcx: TyCtxt<'tcx>, v: ty::IntVid) -> Ty<'tcx> {
+        Ty::new_infer(tcx, IntVar(v))
+    }
+
+    #[inline]
+    pub fn new_float_var(tcx: TyCtxt<'tcx>, v: ty::FloatVid) -> Ty<'tcx> {
+        Ty::new_infer(tcx, FloatVar(v))
+    }
+
+    #[inline]
+    pub fn new_fresh(tcx: TyCtxt<'tcx>, n: u32) -> Ty<'tcx> {
+        // Use a pre-interned one when possible.
+        tcx.types
+            .fresh_tys
+            .get(n as usize)
+            .copied()
+            .unwrap_or_else(|| Ty::new_infer(tcx, ty::FreshTy(n)))
+    }
+
+    #[inline]
+    pub fn new_fresh_int(tcx: TyCtxt<'tcx>, n: u32) -> Ty<'tcx> {
+        // Use a pre-interned one when possible.
+        tcx.types
+            .fresh_int_tys
+            .get(n as usize)
+            .copied()
+            .unwrap_or_else(|| Ty::new_infer(tcx, ty::FreshIntTy(n)))
+    }
+
+    #[inline]
+    pub fn new_fresh_float(tcx: TyCtxt<'tcx>, n: u32) -> Ty<'tcx> {
+        // Use a pre-interned one when possible.
+        tcx.types
+            .fresh_float_tys
+            .get(n as usize)
+            .copied()
+            .unwrap_or_else(|| Ty::new_infer(tcx, ty::FreshFloatTy(n)))
+    }
+
+    #[inline]
+    pub fn new_param(tcx: TyCtxt<'tcx>, index: u32, name: Symbol) -> Ty<'tcx> {
+        tcx.mk_ty_from_kind(Param(ParamTy { index, name }))
+    }
+
+    #[inline]
+    pub fn new_bound(
+        tcx: TyCtxt<'tcx>,
+        index: ty::DebruijnIndex,
+        bound_ty: ty::BoundTy,
+    ) -> Ty<'tcx> {
+        Ty::new(tcx, Bound(index, bound_ty))
+    }
+
+    #[inline]
+    pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderType) -> Ty<'tcx> {
+        Ty::new(tcx, Placeholder(placeholder))
+    }
+
+    #[inline]
+    pub fn new_alias(
+        tcx: TyCtxt<'tcx>,
+        kind: ty::AliasKind,
+        alias_ty: ty::AliasTy<'tcx>,
+    ) -> Ty<'tcx> {
+        debug_assert_matches!(
+            (kind, tcx.def_kind(alias_ty.def_id)),
+            (ty::Opaque, DefKind::OpaqueTy)
+                | (ty::Projection | ty::Inherent, DefKind::AssocTy)
+                | (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder)
+                | (ty::Weak, DefKind::TyAlias)
+        );
+        Ty::new(tcx, Alias(kind, alias_ty))
+    }
+
+    #[inline]
+    pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
+        Ty::new_alias(tcx, ty::Opaque, tcx.mk_alias_ty(def_id, substs))
+    }
+
+    /// Constructs a `TyKind::Error` type with current `ErrorGuaranteed`
+    pub fn new_error(tcx: TyCtxt<'tcx>, reported: ErrorGuaranteed) -> Ty<'tcx> {
+        Ty::new(tcx, Error(reported))
+    }
+
+    /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
+    #[track_caller]
+    pub fn new_misc_error(tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+        Ty::new_error_with_message(tcx, DUMMY_SP, "TyKind::Error constructed but no error reported")
+    }
+
+    /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to
+    /// ensure it gets used.
+    #[track_caller]
+    pub fn new_error_with_message<S: Into<MultiSpan>>(
+        tcx: TyCtxt<'tcx>,
+        span: S,
+        msg: impl Into<DiagnosticMessage>,
+    ) -> Ty<'tcx> {
+        let reported = tcx.sess.delay_span_bug(span, msg);
+        Ty::new(tcx, Error(reported))
+    }
+
+    #[inline]
+    pub fn new_int(tcx: TyCtxt<'tcx>, i: ty::IntTy) -> Ty<'tcx> {
+        use ty::IntTy::*;
+        match i {
+            Isize => tcx.types.isize,
+            I8 => tcx.types.i8,
+            I16 => tcx.types.i16,
+            I32 => tcx.types.i32,
+            I64 => tcx.types.i64,
+            I128 => tcx.types.i128,
+        }
+    }
+
+    #[inline]
+    pub fn new_uint(tcx: TyCtxt<'tcx>, ui: ty::UintTy) -> Ty<'tcx> {
+        use ty::UintTy::*;
+        match ui {
+            Usize => tcx.types.usize,
+            U8 => tcx.types.u8,
+            U16 => tcx.types.u16,
+            U32 => tcx.types.u32,
+            U64 => tcx.types.u64,
+            U128 => tcx.types.u128,
+        }
+    }
+
+    #[inline]
+    pub fn new_float(tcx: TyCtxt<'tcx>, f: ty::FloatTy) -> Ty<'tcx> {
+        use ty::FloatTy::*;
+        match f {
+            F32 => tcx.types.f32,
+            F64 => tcx.types.f64,
+        }
+    }
+
+    #[inline]
+    pub fn new_ref(tcx: TyCtxt<'tcx>, r: Region<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
+        Ty::new(tcx, Ref(r, tm.ty, tm.mutbl))
+    }
+
+    #[inline]
+    pub fn new_mut_ref(tcx: TyCtxt<'tcx>, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+        Ty::new_ref(tcx, r, TypeAndMut { ty, mutbl: hir::Mutability::Mut })
+    }
+
+    #[inline]
+    pub fn new_imm_ref(tcx: TyCtxt<'tcx>, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+        Ty::new_ref(tcx, r, TypeAndMut { ty, mutbl: hir::Mutability::Not })
+    }
+
+    #[inline]
+    pub fn new_ptr(tcx: TyCtxt<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
+        Ty::new(tcx, RawPtr(tm))
+    }
+
+    #[inline]
+    pub fn new_mut_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+        Ty::new_ptr(tcx, TypeAndMut { ty, mutbl: hir::Mutability::Mut })
+    }
+
+    #[inline]
+    pub fn new_imm_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+        Ty::new_ptr(tcx, TypeAndMut { ty, mutbl: hir::Mutability::Not })
+    }
+
+    #[inline]
+    pub fn new_adt(tcx: TyCtxt<'tcx>, def: AdtDef<'tcx>, substs: SubstsRef<'tcx>) -> Ty<'tcx> {
+        Ty::new(tcx, Adt(def, substs))
+    }
+
+    #[inline]
+    pub fn new_foreign(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> {
+        Ty::new(tcx, Foreign(def_id))
+    }
+
+    #[inline]
+    pub fn new_array(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
+        Ty::new(tcx, Array(ty, ty::Const::from_target_usize(tcx, n)))
+    }
+
+    #[inline]
+    pub fn new_array_with_const_len(
+        tcx: TyCtxt<'tcx>,
+        ty: Ty<'tcx>,
+        ct: ty::Const<'tcx>,
+    ) -> Ty<'tcx> {
+        Ty::new(tcx, Array(ty, ct))
+    }
+
+    #[inline]
+    pub fn new_slice(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+        Ty::new(tcx, Slice(ty))
+    }
+
+    #[inline]
+    pub fn new_tup(tcx: TyCtxt<'tcx>, ts: &[Ty<'tcx>]) -> Ty<'tcx> {
+        if ts.is_empty() { tcx.types.unit } else { Ty::new(tcx, Tuple(tcx.mk_type_list(&ts))) }
+    }
+
+    pub fn new_tup_from_iter<I, T>(tcx: TyCtxt<'tcx>, iter: I) -> T::Output
+    where
+        I: Iterator<Item = T>,
+        T: CollectAndApply<Ty<'tcx>, Ty<'tcx>>,
+    {
+        T::collect_and_apply(iter, |ts| Ty::new_tup(tcx, ts))
+    }
+
+    #[inline]
+    pub fn new_fn_def(
+        tcx: TyCtxt<'tcx>,
+        def_id: DefId,
+        substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
+    ) -> Ty<'tcx> {
+        let substs = tcx.check_and_mk_substs(def_id, substs);
+        Ty::new(tcx, FnDef(def_id, substs))
+    }
+
+    #[inline]
+    pub fn new_fn_ptr(tcx: TyCtxt<'tcx>, fty: PolyFnSig<'tcx>) -> Ty<'tcx> {
+        Ty::new(tcx, FnPtr(fty))
+    }
+
+    #[inline]
+    pub fn new_dynamic(
+        tcx: TyCtxt<'tcx>,
+        obj: &'tcx List<PolyExistentialPredicate<'tcx>>,
+        reg: ty::Region<'tcx>,
+        repr: DynKind,
+    ) -> Ty<'tcx> {
+        Ty::new(tcx, Dynamic(obj, reg, repr))
+    }
+
+    #[inline]
+    pub fn new_projection(
+        tcx: TyCtxt<'tcx>,
+        item_def_id: DefId,
+        substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
+    ) -> Ty<'tcx> {
+        Ty::new_alias(tcx, ty::Projection, tcx.mk_alias_ty(item_def_id, substs))
+    }
+
+    #[inline]
+    pub fn new_closure(
+        tcx: TyCtxt<'tcx>,
+        def_id: DefId,
+        closure_substs: SubstsRef<'tcx>,
+    ) -> Ty<'tcx> {
+        debug_assert_eq!(
+            closure_substs.len(),
+            tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 3,
+            "closure constructed with incorrect substitutions"
+        );
+        Ty::new(tcx, Closure(def_id, closure_substs))
+    }
+
+    #[inline]
+    pub fn new_generator(
+        tcx: TyCtxt<'tcx>,
+        def_id: DefId,
+        generator_substs: SubstsRef<'tcx>,
+        movability: hir::Movability,
+    ) -> Ty<'tcx> {
+        debug_assert_eq!(
+            generator_substs.len(),
+            tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5,
+            "generator constructed with incorrect number of substitutions"
+        );
+        Ty::new(tcx, Generator(def_id, generator_substs, movability))
+    }
+
+    #[inline]
+    pub fn new_generator_witness(
+        tcx: TyCtxt<'tcx>,
+        types: ty::Binder<'tcx, &'tcx List<Ty<'tcx>>>,
+    ) -> Ty<'tcx> {
+        Ty::new(tcx, GeneratorWitness(types))
+    }
+
+    #[inline]
+    pub fn new_generator_witness_mir(
+        tcx: TyCtxt<'tcx>,
+        id: DefId,
+        substs: SubstsRef<'tcx>,
+    ) -> Ty<'tcx> {
+        Ty::new(tcx, GeneratorWitnessMIR(id, substs))
+    }
+
+    // misc
+
+    #[inline]
+    pub fn new_unit(tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+        tcx.types.unit
+    }
+
+    #[inline]
+    pub fn new_static_str(tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+        Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, tcx.types.str_)
+    }
+
+    #[inline]
+    pub fn new_diverging_default(tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+        if tcx.features().never_type_fallback { tcx.types.never } else { tcx.types.unit }
+    }
+
+    // lang and diagnostic tys
+
+    fn new_generic_adt(tcx: TyCtxt<'tcx>, wrapper_def_id: DefId, ty_param: Ty<'tcx>) -> Ty<'tcx> {
+        let adt_def = tcx.adt_def(wrapper_def_id);
+        let substs =
+            InternalSubsts::for_item(tcx, wrapper_def_id, |param, substs| match param.kind {
+                GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => bug!(),
+                GenericParamDefKind::Type { has_default, .. } => {
+                    if param.index == 0 {
+                        ty_param.into()
+                    } else {
+                        assert!(has_default);
+                        tcx.type_of(param.def_id).subst(tcx, substs).into()
+                    }
+                }
+            });
+        Ty::new(tcx, Adt(adt_def, substs))
+    }
+
+    #[inline]
+    pub fn new_lang_item(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, item: LangItem) -> Option<Ty<'tcx>> {
+        let def_id = tcx.lang_items().get(item)?;
+        Some(Ty::new_generic_adt(tcx, def_id, ty))
+    }
+
+    #[inline]
+    pub fn new_diagnostic_item(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, name: Symbol) -> Option<Ty<'tcx>> {
+        let def_id = tcx.get_diagnostic_item(name)?;
+        Some(Ty::new_generic_adt(tcx, def_id, ty))
+    }
+
+    #[inline]
+    pub fn new_box(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+        let def_id = tcx.require_lang_item(LangItem::OwnedBox, None);
+        Ty::new_generic_adt(tcx, def_id, ty)
+    }
+
+    #[inline]
+    pub fn new_maybe_uninit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+        let def_id = tcx.require_lang_item(LangItem::MaybeUninit, None);
+        Ty::new_generic_adt(tcx, def_id, ty)
+    }
+
+    /// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes.
+    pub fn new_task_context(tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+        let context_did = tcx.require_lang_item(LangItem::Context, None);
+        let context_adt_ref = tcx.adt_def(context_did);
+        let context_substs = tcx.mk_substs(&[tcx.lifetimes.re_erased.into()]);
+        let context_ty = Ty::new_adt(tcx, context_adt_ref, context_substs);
+        Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, context_ty)
+    }
+}
+
 /// Type utilities
 impl<'tcx> Ty<'tcx> {
     #[inline(always)]
@@ -2316,7 +2704,7 @@ impl<'tcx> Ty<'tcx> {
                 let assoc_items = tcx.associated_item_def_ids(
                     tcx.require_lang_item(hir::LangItem::DiscriminantKind, None),
                 );
-                tcx.mk_projection(assoc_items[0], tcx.mk_substs(&[self.into()]))
+                Ty::new_projection(tcx, assoc_items[0], tcx.mk_substs(&[self.into()]))
             }
 
             ty::Bool
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 46430125106..720d770eed4 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -223,7 +223,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 };
                 let reported =
                     self.sess.emit_err(crate::error::RecursionLimitReached { ty, suggested_limit });
-                return self.ty_error(reported);
+                return Ty::new_error(self, reported);
             }
             match *ty.kind() {
                 ty::Adt(def, substs) => {
@@ -610,12 +610,12 @@ impl<'tcx> TyCtxt<'tcx> {
         closure_substs: SubstsRef<'tcx>,
         env_region: ty::Region<'tcx>,
     ) -> Option<Ty<'tcx>> {
-        let closure_ty = self.mk_closure(closure_def_id, closure_substs);
+        let closure_ty = Ty::new_closure(self, closure_def_id, closure_substs);
         let closure_kind_ty = closure_substs.as_closure().kind_ty();
         let closure_kind = closure_kind_ty.to_opt_closure_kind()?;
         let env_ty = match closure_kind {
-            ty::ClosureKind::Fn => self.mk_imm_ref(env_region, closure_ty),
-            ty::ClosureKind::FnMut => self.mk_mut_ref(env_region, closure_ty),
+            ty::ClosureKind::Fn => Ty::new_imm_ref(self, env_region, closure_ty),
+            ty::ClosureKind::FnMut => Ty::new_mut_ref(self, env_region, closure_ty),
             ty::ClosureKind::FnOnce => closure_ty,
         };
         Some(env_ty)
@@ -656,12 +656,12 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn thread_local_ptr_ty(self, def_id: DefId) -> Ty<'tcx> {
         let static_ty = self.type_of(def_id).subst_identity();
         if self.is_mutable_static(def_id) {
-            self.mk_mut_ptr(static_ty)
+            Ty::new_mut_ptr(self, static_ty)
         } else if self.is_foreign_item(def_id) {
-            self.mk_imm_ptr(static_ty)
+            Ty::new_imm_ptr(self, static_ty)
         } else {
             // FIXME: These things don't *really* have 'static lifetime.
-            self.mk_imm_ref(self.lifetimes.re_static, static_ty)
+            Ty::new_imm_ref(self, self.lifetimes.re_static, static_ty)
         }
     }
 
@@ -676,11 +676,11 @@ impl<'tcx> TyCtxt<'tcx> {
         // Make sure that accesses to unsafe statics end up using raw pointers.
         // For thread-locals, this needs to be kept in sync with `Rvalue::ty`.
         if self.is_mutable_static(def_id) {
-            self.mk_mut_ptr(static_ty)
+            Ty::new_mut_ptr(self, static_ty)
         } else if self.is_foreign_item(def_id) {
-            self.mk_imm_ptr(static_ty)
+            Ty::new_imm_ptr(self, static_ty)
         } else {
-            self.mk_imm_ref(self.lifetimes.re_erased, static_ty)
+            Ty::new_imm_ref(self, self.lifetimes.re_erased, static_ty)
         }
     }
 
@@ -854,7 +854,7 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
                         let hidden_ty = bty.subst(self.tcx, substs);
                         self.fold_ty(hidden_ty);
                     }
-                    let expanded_ty = self.tcx.mk_generator_witness_mir(def_id, substs);
+                    let expanded_ty = Ty::new_generator_witness_mir(self.tcx, def_id, substs);
                     self.expanded_cache.insert((def_id, substs), expanded_ty);
                     expanded_ty
                 }
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index 8758cd04d67..b0961d91787 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -16,7 +16,7 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Ty<'_> {
     fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo<DepKind>]) -> Self {
         // SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
         // FIXME: Represent the above fact in the trait system somehow.
-        unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.ty_error_misc()) }
+        unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_misc_error(tcx)) }
     }
 }
 
@@ -34,7 +34,7 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> {
 
 impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> {
     fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo<DepKind>]) -> Self {
-        let err = tcx.ty_error_misc();
+        let err = Ty::new_misc_error(tcx);
 
         let arity = if let Some(frame) = stack.get(0)
             && frame.query.dep_kind == DepKind::fn_sig
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 783f6e2085c..ac2d099be50 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -683,7 +683,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     ProjectionElem::Deref => {
                         let fake_borrow_deref_ty = base_place.ty(&self.local_decls, tcx).ty;
                         let fake_borrow_ty =
-                            tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
+                            Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fake_borrow_deref_ty);
                         let fake_borrow_temp =
                             self.local_decls.push(LocalDecl::new(fake_borrow_ty, expr_span));
                         let projection = tcx.mk_place_elems(&base_place.projection);
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 27b1b58d2e9..5c886ac4d9b 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -162,7 +162,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     [],
                     expr_span,
                 );
-                let storage = this.temp(tcx.mk_mut_ptr(tcx.types.u8), expr_span);
+                let storage = this.temp(Ty::new_mut_ptr(tcx, tcx.types.u8), expr_span);
                 let success = this.cfg.start_new_block();
                 this.cfg.terminate(
                     block,
@@ -564,7 +564,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let bool_ty = self.tcx.types.bool;
         let rvalue = match op {
             BinOp::Add | BinOp::Sub | BinOp::Mul if self.check_overflow && ty.is_integral() => {
-                let result_tup = self.tcx.mk_tup(&[ty, bool_ty]);
+                let result_tup = Ty::new_tup(self.tcx, &[ty, bool_ty]);
                 let result_value = self.temp(result_tup, span);
 
                 self.cfg.push_assign(
@@ -598,7 +598,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let (unsigned_rhs, unsigned_ty) = match rhs_ty.kind() {
                     ty::Uint(_) => (rhs.to_copy(), rhs_ty),
                     ty::Int(int_width) => {
-                        let uint_ty = self.tcx.mk_mach_uint(int_width.to_unsigned());
+                        let uint_ty = Ty::new_uint(self.tcx, int_width.to_unsigned());
                         let rhs_temp = self.temp(uint_ty, span);
                         self.cfg.push_assign(
                             block,
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 6df06df5c60..10770213c9a 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -1751,7 +1751,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     projection: tcx.mk_place_elems(matched_place_ref.projection),
                 };
                 let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty;
-                let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
+                let fake_borrow_ty =
+                    Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fake_borrow_deref_ty);
                 let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span);
                 fake_borrow_temp.internal = self.local_decls[matched_place.local].internal;
                 fake_borrow_temp.local_info = ClearCrossCrate::Set(Box::new(LocalInfo::FakeBorrow));
@@ -2250,7 +2251,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // This variable isn't mutated but has a name, so has to be
                 // immutable to avoid the unused mut lint.
                 mutability: Mutability::Not,
-                ty: tcx.mk_imm_ref(tcx.lifetimes.re_erased, var_ty),
+                ty: Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, var_ty),
                 user_ty: None,
                 source_info,
                 internal: false,
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index f431023f2b6..3a2c506bb98 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -244,8 +244,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         bug!("matching on `String` went through without enabling string_deref_patterns");
                     }
                     let re_erased = tcx.lifetimes.re_erased;
-                    let ref_string = self.temp(tcx.mk_imm_ref(re_erased, ty), test.span);
-                    let ref_str_ty = tcx.mk_imm_ref(re_erased, tcx.types.str_);
+                    let ref_string = self.temp(Ty::new_imm_ref(tcx,re_erased, ty), test.span);
+                    let ref_str_ty = Ty::new_imm_ref(tcx,re_erased, tcx.types.str_);
                     let ref_str = self.temp(ref_str_ty, test.span);
                     let deref = tcx.require_lang_item(LangItem::Deref, None);
                     let method = trait_method(tcx, deref, sym::deref, [ty]);
@@ -415,7 +415,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             (Some((region, elem_ty, _)), _) | (None, Some((region, elem_ty, _))) => {
                 let tcx = self.tcx;
                 // make both a slice
-                ty = tcx.mk_imm_ref(*region, tcx.mk_slice(*elem_ty));
+                ty = Ty::new_imm_ref(tcx, *region, Ty::new_slice(tcx, *elem_ty));
                 if opt_ref_ty.is_some() {
                     let temp = self.temp(ty, source_info.span);
                     self.cfg.push_assign(
@@ -449,7 +449,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // non_scalar_compare called on non-reference type
                 let temp = self.temp(ty, source_info.span);
                 self.cfg.push_assign(block, source_info, temp, Rvalue::Use(expect));
-                let ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, ty);
+                let ref_ty = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, ty);
                 let ref_temp = self.temp(ref_ty, source_info.span);
 
                 self.cfg.push_assign(
@@ -871,7 +871,7 @@ fn trait_method<'tcx>(
         .find(|item| item.kind == ty::AssocKind::Fn)
         .expect("trait method not found");
 
-    let method_ty = tcx.mk_fn_def(item.def_id, substs);
+    let method_ty = Ty::new_fn_def(tcx, item.def_id, substs);
 
     ConstantKind::zero_sized(method_ty)
 }
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 49cbe3e2c9b..d828e71c7ac 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -614,7 +614,7 @@ fn construct_error(tcx: TyCtxt<'_>, def: LocalDefId, err: ErrorGuaranteed) -> Bo
     let generator_kind = tcx.generator_kind(def);
     let body_owner_kind = tcx.hir().body_owner_kind(def);
 
-    let ty = tcx.ty_error(err);
+    let ty = Ty::new_error(tcx, err);
     let num_params = match body_owner_kind {
         hir::BodyOwnerKind::Fn => tcx.fn_sig(def).skip_binder().inputs().skip_binder().len(),
         hir::BodyOwnerKind::Closure => {
@@ -942,7 +942,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         match self.unit_temp {
             Some(tmp) => tmp,
             None => {
-                let ty = self.tcx.mk_unit();
+                let ty = Ty::new_unit(self.tcx);
                 let fn_span = self.fn_span;
                 let tmp = self.temp(ty, fn_span);
                 self.unit_temp = Some(tmp);
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 7c0fbc6f81c..72374102c8c 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -91,6 +91,7 @@ use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::thir::{Expr, LintLevel};
 
+use rustc_middle::ty::Ty;
 use rustc_span::{Span, DUMMY_SP};
 
 #[derive(Debug)]
@@ -724,7 +725,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     // Add a dummy `Assign` statement to the CFG, with the span for the source code's `continue`
     // statement.
     fn add_dummy_assignment(&mut self, span: Span, block: BasicBlock, source_info: SourceInfo) {
-        let local_decl = LocalDecl::new(self.tcx.mk_unit(), span).internal();
+        let local_decl = LocalDecl::new(Ty::new_unit(self.tcx), span).internal();
         let temp_place = Place::from(self.local_decls.push(local_decl));
         self.cfg.push_assign_unit(block, source_info, temp_place, self.tcx);
     }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 791c10c1748..a5c141b71f6 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -143,9 +143,11 @@ impl<'tcx> Cx<'tcx> {
 
                 expr = Expr {
                     temp_lifetime,
-                    ty: self
-                        .tcx
-                        .mk_ref(deref.region, ty::TypeAndMut { ty: expr.ty, mutbl: deref.mutbl }),
+                    ty: Ty::new_ref(
+                        self.tcx,
+                        deref.region,
+                        ty::TypeAndMut { ty: expr.ty, mutbl: deref.mutbl },
+                    ),
                     span,
                     kind: ExprKind::Borrow {
                         borrow_kind: deref.mutbl.to_borrow_kind(),
@@ -308,7 +310,7 @@ impl<'tcx> Cx<'tcx> {
 
                     let arg_tys = args.iter().map(|e| self.typeck_results().expr_ty_adjusted(e));
                     let tupled_args = Expr {
-                        ty: tcx.mk_tup_from_iter(arg_tys),
+                        ty: Ty::new_tup_from_iter(tcx, arg_tys),
                         temp_lifetime,
                         span: expr.span,
                         kind: ExprKind::Tuple { fields: self.mirror_exprs(args) },
@@ -855,7 +857,11 @@ impl<'tcx> Cx<'tcx> {
                 let user_ty = self.user_substs_applied_to_res(expr.hir_id, Res::Def(kind, def_id));
                 debug!("method_callee: user_ty={:?}", user_ty);
                 (
-                    self.tcx().mk_fn_def(def_id, self.typeck_results().node_substs(expr.hir_id)),
+                    Ty::new_fn_def(
+                        self.tcx(),
+                        def_id,
+                        self.typeck_results().node_substs(expr.hir_id),
+                    ),
                     user_ty,
                 )
             }
@@ -1008,7 +1014,7 @@ impl<'tcx> Cx<'tcx> {
         let ty::Ref(region, _, mutbl) = *self.thir[args[0]].ty.kind() else {
             span_bug!(span, "overloaded_place: receiver is not a reference");
         };
-        let ref_ty = self.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl });
+        let ref_ty = Ty::new_ref(self.tcx, region, ty::TypeAndMut { ty: place_ty, mutbl });
 
         // construct the complete expression `foo()` for the overloaded call,
         // which will yield the &T type
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index d00fb754c64..e6a98d1aab0 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -15,7 +15,7 @@ use rustc_hir::HirId;
 use rustc_hir::Node;
 use rustc_middle::middle::region;
 use rustc_middle::thir::*;
-use rustc_middle::ty::{self, RvalueScopes, TyCtxt};
+use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt};
 use rustc_span::Span;
 
 pub(crate) fn thir_body(
@@ -40,7 +40,7 @@ pub(crate) fn thir_body(
         // It will always be `()` in this case.
         if tcx.def_kind(owner_def) == DefKind::Generator && body.params.is_empty() {
             cx.thir.params.push(Param {
-                ty: tcx.mk_unit(),
+                ty: Ty::new_unit(tcx),
                 pat: None,
                 ty_span: None,
                 self_kind: None,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 8fadcc456c1..050b01294b4 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -429,7 +429,7 @@ impl<'tcx> ConstToPat<'tcx> {
                         // arrays.
                         let pointee_ty = match *pointee_ty.kind() {
                             ty::Array(elem_ty, _) if self.treat_byte_string_as_slice => {
-                                tcx.mk_slice(elem_ty)
+                                Ty::new_slice(tcx, elem_ty)
                             }
                             _ => *pointee_ty,
                         };
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index c0102b15a16..0540a5e943b 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -423,7 +423,7 @@ where
         let unique_ty = adt.non_enum_variant().fields[FieldIdx::new(0)].ty(self.tcx(), substs);
         let unique_variant = unique_ty.ty_adt_def().unwrap().non_enum_variant();
         let nonnull_ty = unique_variant.fields[FieldIdx::from_u32(0)].ty(self.tcx(), substs);
-        let ptr_ty = self.tcx().mk_imm_ptr(substs[0].expect_ty());
+        let ptr_ty = Ty::new_imm_ptr(self.tcx(), substs[0].expect_ty());
 
         let unique_place = self.tcx().mk_place_field(self.place, FieldIdx::new(0), unique_ty);
         let nonnull_place = self.tcx().mk_place_field(unique_place, FieldIdx::new(0), nonnull_ty);
@@ -628,10 +628,13 @@ where
         let drop_fn = tcx.associated_item_def_ids(drop_trait)[0];
         let ty = self.place_ty(self.place);
 
-        let ref_ty =
-            tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut });
+        let ref_ty = Ty::new_ref(
+            tcx,
+            tcx.lifetimes.re_erased,
+            ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut },
+        );
         let ref_place = self.new_temp(ref_ty);
-        let unit_temp = Place::from(self.new_temp(tcx.mk_unit()));
+        let unit_temp = Place::from(self.new_temp(Ty::new_unit(tcx)));
 
         let result = BasicBlockData {
             statements: vec![self.assign(
@@ -693,7 +696,7 @@ where
         let move_ = |place: Place<'tcx>| Operand::Move(place);
         let tcx = self.tcx();
 
-        let ptr_ty = tcx.mk_ptr(ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::Mut });
+        let ptr_ty = Ty::new_ptr(tcx, ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::Mut });
         let ptr = Place::from(self.new_temp(ptr_ty));
         let can_go = Place::from(self.new_temp(tcx.types.bool));
         let one = self.constant_usize(1);
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index 05c54ab3097..4892ace53e3 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -155,7 +155,7 @@ fn insert_alignment_check<'tcx>(
     new_block: BasicBlock,
 ) {
     // Cast the pointer to a *const ()
-    let const_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not });
+    let const_raw_ptr = Ty::new_ptr(tcx, TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not });
     let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr);
     let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into();
     block_data
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index f31653caa49..cc0d7d51b60 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -21,7 +21,7 @@ pub fn build_ptr_tys<'tcx>(
     let substs = tcx.mk_substs(&[pointee.into()]);
     let unique_ty = tcx.type_of(unique_did).subst(tcx, substs);
     let nonnull_ty = tcx.type_of(nonnull_did).subst(tcx, substs);
-    let ptr_ty = tcx.mk_imm_ptr(pointee);
+    let ptr_ty = Ty::new_imm_ptr(tcx, pointee);
 
     (unique_ty, nonnull_ty, ptr_ty)
 }
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 029fb2e9ba0..264bc61f1b3 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -413,8 +413,11 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
 fn make_generator_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     let gen_ty = body.local_decls.raw[1].ty;
 
-    let ref_gen_ty =
-        tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty: gen_ty, mutbl: Mutability::Mut });
+    let ref_gen_ty = Ty::new_ref(
+        tcx,
+        tcx.lifetimes.re_erased,
+        ty::TypeAndMut { ty: gen_ty, mutbl: Mutability::Mut },
+    );
 
     // Replace the by value generator argument
     body.local_decls.raw[1].ty = ref_gen_ty;
@@ -429,7 +432,7 @@ fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body
     let pin_did = tcx.require_lang_item(LangItem::Pin, Some(body.span));
     let pin_adt_ref = tcx.adt_def(pin_did);
     let substs = tcx.mk_substs(&[ref_gen_ty.into()]);
-    let pin_ref_gen_ty = tcx.mk_adt(pin_adt_ref, substs);
+    let pin_ref_gen_ty = Ty::new_adt(tcx, pin_adt_ref, substs);
 
     // Replace the by ref generator argument
     body.local_decls.raw[1].ty = pin_ref_gen_ty;
@@ -481,7 +484,7 @@ fn replace_local<'tcx>(
 /// still using the `ResumeTy` indirection for the time being, and that indirection
 /// is removed here. After this transform, the generator body only knows about `&mut Context<'_>`.
 fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    let context_mut_ref = tcx.mk_task_context();
+    let context_mut_ref = Ty::new_task_context(tcx);
 
     // replace the type of the `resume` argument
     replace_resume_ty_local(tcx, body, Local::new(2), context_mut_ref);
@@ -1130,13 +1133,13 @@ fn create_generator_drop_shim<'tcx>(
     }
 
     // Replace the return variable
-    body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(tcx.mk_unit(), source_info);
+    body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(Ty::new_unit(tcx), source_info);
 
     make_generator_state_argument_indirect(tcx, &mut body);
 
     // Change the generator argument from &mut to *mut
     body.local_decls[SELF_ARG] = LocalDecl::with_source_info(
-        tcx.mk_ptr(ty::TypeAndMut { ty: gen_ty, mutbl: hir::Mutability::Mut }),
+        Ty::new_ptr(tcx, ty::TypeAndMut { ty: gen_ty, mutbl: hir::Mutability::Mut }),
         source_info,
     );
 
@@ -1493,7 +1496,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
             let state_substs = tcx.mk_substs(&[yield_ty.into(), body.return_ty().into()]);
             (state_adt_ref, state_substs)
         };
-        let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
+        let ret_ty = Ty::new_adt(tcx, state_adt_ref, state_substs);
 
         // We rename RETURN_PLACE which has type mir.return_ty to new_ret_local
         // RETURN_PLACE then is a fresh unused local with type ret_ty.
@@ -1509,8 +1512,11 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
         // case there is no `Assign` to it that the transform can turn into a store to the generator
         // state. After the yield the slot in the generator state would then be uninitialized.
         let resume_local = Local::new(2);
-        let resume_ty =
-            if is_async_kind { tcx.mk_task_context() } else { body.local_decls[resume_local].ty };
+        let resume_ty = if is_async_kind {
+            Ty::new_task_context(tcx)
+        } else {
+            body.local_decls[resume_local].ty
+        };
         let new_resume_local = replace_local(resume_local, resume_ty, body, tcx);
 
         // When first entering the generator, move the resume argument into its new local.
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
index 430a6f6cef5..8ed4706e172 100644
--- a/compiler/rustc_mir_transform/src/large_enums.rs
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -141,7 +141,7 @@ impl EnumSizeOpt {
                         self.candidate(tcx, param_env, ty, &mut alloc_cache)?;
                     let alloc = tcx.global_alloc(alloc_id).unwrap_memory();
 
-                    let tmp_ty = tcx.mk_array(tcx.types.usize, num_variants as u64);
+                    let tmp_ty = Ty::new_array(tcx, tcx.types.usize, num_variants as u64);
 
                     let size_array_local = local_decls.push(LocalDecl::new(tmp_ty, span));
                     let store_live = Statement {
@@ -208,8 +208,9 @@ impl EnumSizeOpt {
                         ))),
                     };
 
-                    let dst =
-                        Place::from(local_decls.push(LocalDecl::new(tcx.mk_mut_ptr(ty), span)));
+                    let dst = Place::from(
+                        local_decls.push(LocalDecl::new(Ty::new_mut_ptr(tcx, ty), span)),
+                    );
 
                     let dst_ptr = Statement {
                         source_info,
@@ -219,7 +220,7 @@ impl EnumSizeOpt {
                         ))),
                     };
 
-                    let dst_cast_ty = tcx.mk_mut_ptr(tcx.types.u8);
+                    let dst_cast_ty = Ty::new_mut_ptr(tcx, tcx.types.u8);
                     let dst_cast_place =
                         Place::from(local_decls.push(LocalDecl::new(dst_cast_ty, span)));
 
@@ -231,8 +232,9 @@ impl EnumSizeOpt {
                         ))),
                     };
 
-                    let src =
-                        Place::from(local_decls.push(LocalDecl::new(tcx.mk_imm_ptr(ty), span)));
+                    let src = Place::from(
+                        local_decls.push(LocalDecl::new(Ty::new_imm_ptr(tcx, ty), span)),
+                    );
 
                     let src_ptr = Statement {
                         source_info,
@@ -242,7 +244,7 @@ impl EnumSizeOpt {
                         ))),
                     };
 
-                    let src_cast_ty = tcx.mk_imm_ptr(tcx.types.u8);
+                    let src_cast_ty = Ty::new_imm_ptr(tcx, tcx.types.u8);
                     let src_cast_place =
                         Place::from(local_decls.push(LocalDecl::new(src_cast_ty, span)));
 
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 500595e9f50..b176db3c9e0 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -485,7 +485,7 @@ impl<'tcx> CloneShimBuilder<'tcx> {
         let tcx = self.tcx;
 
         // `func == Clone::clone(&ty) -> ty`
-        let func_ty = tcx.mk_fn_def(self.def_id, [ty]);
+        let func_ty = Ty::new_fn_def(tcx, self.def_id, [ty]);
         let func = Operand::Constant(Box::new(Constant {
             span: self.span,
             user_ty: None,
@@ -494,7 +494,11 @@ impl<'tcx> CloneShimBuilder<'tcx> {
 
         let ref_loc = self.make_place(
             Mutability::Not,
-            tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::Not }),
+            Ty::new_ref(
+                tcx,
+                tcx.lifetimes.re_erased,
+                ty::TypeAndMut { ty, mutbl: hir::Mutability::Not },
+            ),
         );
 
         // `let ref_loc: &ty = &src;`
@@ -644,7 +648,7 @@ fn build_call_shim<'tcx>(
         let untuple_args = sig.inputs();
 
         // Create substitutions for the `Self` and `Args` generic parameters of the shim body.
-        let arg_tup = tcx.mk_tup(untuple_args);
+        let arg_tup = Ty::new_tup(tcx, untuple_args);
 
         (Some([ty.into(), arg_tup.into()]), Some(untuple_args))
     } else {
@@ -680,9 +684,9 @@ fn build_call_shim<'tcx>(
         *self_arg = match rcvr_adjustment.unwrap() {
             Adjustment::Identity => fnty,
             Adjustment::Deref { source } => match source {
-                DerefSource::ImmRef => tcx.mk_imm_ref(tcx.lifetimes.re_erased, fnty),
-                DerefSource::MutRef => tcx.mk_mut_ref(tcx.lifetimes.re_erased, fnty),
-                DerefSource::MutPtr => tcx.mk_mut_ptr(fnty),
+                DerefSource::ImmRef => Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, fnty),
+                DerefSource::MutRef => Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, fnty),
+                DerefSource::MutPtr => Ty::new_mut_ptr(tcx, fnty),
             },
             Adjustment::RefMut => bug!("`RefMut` is never used with indirect calls: {instance:?}"),
         };
@@ -696,7 +700,7 @@ fn build_call_shim<'tcx>(
         let mut inputs_and_output = sig.inputs_and_output.to_vec();
         let self_arg = &mut inputs_and_output[0];
         debug_assert!(tcx.generics_of(def_id).has_self && *self_arg == tcx.types.self_param);
-        *self_arg = tcx.mk_mut_ptr(*self_arg);
+        *self_arg = Ty::new_mut_ptr(tcx, *self_arg);
         sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
     }
 
@@ -720,7 +724,8 @@ fn build_call_shim<'tcx>(
             // let rcvr = &mut rcvr;
             let ref_rcvr = local_decls.push(
                 LocalDecl::new(
-                    tcx.mk_ref(
+                    Ty::new_ref(
+                        tcx,
                         tcx.lifetimes.re_erased,
                         ty::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::Mut },
                     ),
@@ -946,7 +951,7 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t
     let rvalue = Rvalue::Cast(
         CastKind::FnPtrToPtr,
         Operand::Move(Place::from(Local::new(1))),
-        tcx.mk_imm_ptr(tcx.types.unit),
+        Ty::new_imm_ptr(tcx, tcx.types.unit),
     );
     let stmt = Statement {
         source_info,
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 2f978102ff2..3b46275ec41 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -643,7 +643,7 @@ fn encode_ty<'tcx>(
             s.push_str("u3refI");
             s.push_str(&encode_ty(tcx, *ty0, dict, options));
             s.push('E');
-            compress(dict, DictKey::Ty(tcx.mk_imm_ref(*region, *ty0), TyQ::None), &mut s);
+            compress(dict, DictKey::Ty(Ty::new_imm_ref(tcx, *region, *ty0), TyQ::None), &mut s);
             if ty.is_mutable_ptr() {
                 s = format!("{}{}", "U3mut", &s);
                 compress(dict, DictKey::Ty(ty, TyQ::Mut), &mut s);
@@ -739,7 +739,7 @@ fn transform_substs<'tcx>(
     options: TransformTyOptions,
 ) -> SubstsRef<'tcx> {
     let substs = substs.iter().map(|subst| match subst.unpack() {
-        GenericArgKind::Type(ty) if ty.is_c_void(tcx) => tcx.mk_unit().into(),
+        GenericArgKind::Type(ty) if ty.is_c_void(tcx) => Ty::new_unit(tcx).into(),
         GenericArgKind::Type(ty) => transform_ty(tcx, ty, options).into(),
         _ => subst,
     });
@@ -809,7 +809,7 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
         _ if ty.is_unit() => {}
 
         ty::Tuple(tys) => {
-            ty = tcx.mk_tup_from_iter(tys.iter().map(|ty| transform_ty(tcx, ty, options)));
+            ty = Ty::new_tup_from_iter(tcx, tys.iter().map(|ty| transform_ty(tcx, ty, options)));
         }
 
         ty::Array(ty0, len) => {
@@ -818,19 +818,19 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
                 .unwrap()
                 .to_u64()
                 .unwrap_or_else(|_| panic!("failed to convert length to u64"));
-            ty = tcx.mk_array(transform_ty(tcx, *ty0, options), len);
+            ty = Ty::new_array(tcx, transform_ty(tcx, *ty0, options), len);
         }
 
         ty::Slice(ty0) => {
-            ty = tcx.mk_slice(transform_ty(tcx, *ty0, options));
+            ty = Ty::new_slice(tcx, transform_ty(tcx, *ty0, options));
         }
 
         ty::Adt(adt_def, substs) => {
             if ty.is_c_void(tcx) {
-                ty = tcx.mk_unit();
+                ty = Ty::new_unit(tcx);
             } else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c()
             {
-                ty = tcx.mk_adt(*adt_def, ty::List::empty());
+                ty = Ty::new_adt(tcx, *adt_def, ty::List::empty());
             } else if adt_def.repr().transparent() && adt_def.is_struct() {
                 // Don't transform repr(transparent) types with an user-defined CFI encoding to
                 // preserve the user-defined CFI encoding.
@@ -861,37 +861,42 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
                     }
                 } else {
                     // Transform repr(transparent) types without non-ZST field into ()
-                    ty = tcx.mk_unit();
+                    ty = Ty::new_unit(tcx);
                 }
             } else {
-                ty = tcx.mk_adt(*adt_def, transform_substs(tcx, substs, options));
+                ty = Ty::new_adt(tcx, *adt_def, transform_substs(tcx, substs, options));
             }
         }
 
         ty::FnDef(def_id, substs) => {
-            ty = tcx.mk_fn_def(*def_id, transform_substs(tcx, substs, options));
+            ty = Ty::new_fn_def(tcx, *def_id, transform_substs(tcx, substs, options));
         }
 
         ty::Closure(def_id, substs) => {
-            ty = tcx.mk_closure(*def_id, transform_substs(tcx, substs, options));
+            ty = Ty::new_closure(tcx, *def_id, transform_substs(tcx, substs, options));
         }
 
         ty::Generator(def_id, substs, movability) => {
-            ty = tcx.mk_generator(*def_id, transform_substs(tcx, substs, options), *movability);
+            ty = Ty::new_generator(
+                tcx,
+                *def_id,
+                transform_substs(tcx, substs, options),
+                *movability,
+            );
         }
 
         ty::Ref(region, ty0, ..) => {
             if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
                 if ty.is_mutable_ptr() {
-                    ty = tcx.mk_mut_ref(tcx.lifetimes.re_static, tcx.mk_unit());
+                    ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx));
                 } else {
-                    ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_unit());
+                    ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_unit(tcx));
                 }
             } else {
                 if ty.is_mutable_ptr() {
-                    ty = tcx.mk_mut_ref(*region, transform_ty(tcx, *ty0, options));
+                    ty = Ty::new_mut_ref(tcx, *region, transform_ty(tcx, *ty0, options));
                 } else {
-                    ty = tcx.mk_imm_ref(*region, transform_ty(tcx, *ty0, options));
+                    ty = Ty::new_imm_ref(tcx, *region, transform_ty(tcx, *ty0, options));
                 }
             }
         }
@@ -899,22 +904,22 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
         ty::RawPtr(tm) => {
             if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
                 if ty.is_mutable_ptr() {
-                    ty = tcx.mk_mut_ptr(tcx.mk_unit());
+                    ty = Ty::new_mut_ptr(tcx, Ty::new_unit(tcx));
                 } else {
-                    ty = tcx.mk_imm_ptr(tcx.mk_unit());
+                    ty = Ty::new_imm_ptr(tcx, Ty::new_unit(tcx));
                 }
             } else {
                 if ty.is_mutable_ptr() {
-                    ty = tcx.mk_mut_ptr(transform_ty(tcx, tm.ty, options));
+                    ty = Ty::new_mut_ptr(tcx, transform_ty(tcx, tm.ty, options));
                 } else {
-                    ty = tcx.mk_imm_ptr(transform_ty(tcx, tm.ty, options));
+                    ty = Ty::new_imm_ptr(tcx, transform_ty(tcx, tm.ty, options));
                 }
             }
         }
 
         ty::FnPtr(fn_sig) => {
             if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
-                ty = tcx.mk_imm_ptr(tcx.mk_unit());
+                ty = Ty::new_imm_ptr(tcx, Ty::new_unit(tcx));
             } else {
                 let parameters: Vec<Ty<'tcx>> = fn_sig
                     .skip_binder()
@@ -923,21 +928,25 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
                     .map(|ty| transform_ty(tcx, *ty, options))
                     .collect();
                 let output = transform_ty(tcx, fn_sig.skip_binder().output(), options);
-                ty = tcx.mk_fn_ptr(ty::Binder::bind_with_vars(
-                    tcx.mk_fn_sig(
-                        parameters,
-                        output,
-                        fn_sig.c_variadic(),
-                        fn_sig.unsafety(),
-                        fn_sig.abi(),
+                ty = Ty::new_fn_ptr(
+                    tcx,
+                    ty::Binder::bind_with_vars(
+                        tcx.mk_fn_sig(
+                            parameters,
+                            output,
+                            fn_sig.c_variadic(),
+                            fn_sig.unsafety(),
+                            fn_sig.abi(),
+                        ),
+                        fn_sig.bound_vars(),
                     ),
-                    fn_sig.bound_vars(),
-                ));
+                );
             }
         }
 
         ty::Dynamic(predicates, _region, kind) => {
-            ty = tcx.mk_dynamic(
+            ty = Ty::new_dynamic(
+                tcx,
                 transform_predicates(tcx, predicates, options),
                 tcx.lifetimes.re_erased,
                 *kind,
@@ -1106,14 +1115,16 @@ pub fn typeid_for_instance<'tcx>(
             )]);
             // Is the concrete self mutable?
             let self_ty = if fn_abi.args[0].layout.ty.is_mutable_ptr() {
-                tcx.mk_mut_ref(
+                Ty::new_mut_ref(
+                    tcx,
                     tcx.lifetimes.re_erased,
-                    tcx.mk_dynamic(existential_predicates, tcx.lifetimes.re_erased, ty::Dyn),
+                    Ty::new_dynamic(tcx, existential_predicates, tcx.lifetimes.re_erased, ty::Dyn),
                 )
             } else {
-                tcx.mk_imm_ref(
+                Ty::new_imm_ref(
+                    tcx,
                     tcx.lifetimes.re_erased,
-                    tcx.mk_dynamic(existential_predicates, tcx.lifetimes.re_erased, ty::Dyn),
+                    Ty::new_dynamic(tcx, existential_predicates, tcx.lifetimes.re_erased, ty::Dyn),
                 )
             };
 
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index d1d5af48957..5e5cc6e4e4a 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -535,7 +535,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
                 match predicate.as_ref().skip_binder() {
                     ty::ExistentialPredicate::Trait(trait_ref) => {
                         // Use a type that can't appear in defaults of type parameters.
-                        let dummy_self = cx.tcx.mk_fresh_ty(0);
+                        let dummy_self = Ty::new_fresh(cx.tcx, 0);
                         let trait_ref = trait_ref.with_self_ty(cx.tcx, dummy_self);
                         cx = cx.print_def_path(trait_ref.def_id, trait_ref.substs)?;
                     }
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 9eac53c3983..3bb8cad15ab 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -28,7 +28,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
         | ty::Char => Ok(vec![]),
 
         // Treat `str` like it's defined as `struct str([u8]);`
-        ty::Str => Ok(vec![tcx.mk_slice(tcx.types.u8)]),
+        ty::Str => Ok(vec![Ty::new_slice(tcx, tcx.types.u8)]),
 
         ty::Dynamic(..)
         | ty::Param(..)
@@ -233,7 +233,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
             {
                 Ok(Some(
                     sig.subst(tcx, substs)
-                        .map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())),
+                        .map_bound(|sig| (Ty::new_tup(tcx, sig.inputs()), sig.output())),
                 ))
             } else {
                 Err(NoSolution)
@@ -242,7 +242,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
         // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
         ty::FnPtr(sig) => {
             if sig.is_fn_trait_compatible() {
-                Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output()))))
+                Ok(Some(sig.map_bound(|sig| (Ty::new_tup(tcx, sig.inputs()), sig.output()))))
             } else {
                 Err(NoSolution)
             }
diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
index e53151baa1f..255620489ff 100644
--- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
@@ -283,7 +283,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
                 // any equated inference vars correctly!
                 let root_vid = self.infcx.root_var(vid);
                 if root_vid != vid {
-                    t = self.infcx.tcx.mk_ty_var(root_vid);
+                    t = Ty::new_var(self.infcx.tcx, root_vid);
                     vid = root_vid;
                 }
 
@@ -366,7 +366,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
             }),
         );
         let bt = ty::BoundTy { var, kind: BoundTyKind::Anon };
-        self.interner().mk_bound(self.binder_index, bt)
+        Ty::new_bound(self.infcx.tcx, self.binder_index, bt)
     }
 
     fn fold_const(&mut self, mut c: ty::Const<'tcx>) -> ty::Const<'tcx> {
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index c19d57788fe..aa690719970 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -187,7 +187,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                                 .subst(tcx, goal.predicate.projection_ty.substs),
                             )
                             .into(),
-                        ty::AssocKind::Type => tcx.ty_error(guar).into(),
+                        ty::AssocKind::Type => Ty::new_error(tcx,guar).into(),
                         ty::AssocKind::Fn => unreachable!(),
                     };
                     ecx.eq(goal.param_env, goal.predicate.term, error_term)
@@ -343,7 +343,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
                 | ty::Never
                 | ty::Foreign(..) => tcx.types.unit,
 
-                ty::Error(e) => tcx.ty_error(*e),
+                ty::Error(e) => Ty::new_error(tcx, *e),
 
                 ty::Str | ty::Slice(_) => tcx.types.usize,
 
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index a2eb223bc26..7ff47295e7c 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -416,7 +416,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                         tcx.mk_substs_from_iter(a_substs.iter().enumerate().map(|(i, a)| {
                             if unsizing_params.contains(i as u32) { b_substs[i] } else { a }
                         }));
-                    let unsized_a_ty = tcx.mk_adt(a_def, new_a_substs);
+                    let unsized_a_ty = Ty::new_adt(tcx, a_def, new_a_substs);
 
                     // Finally, we require that `TailA: Unsize<TailB>` for the tail field
                     // types.
@@ -436,7 +436,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
 
                     // Substitute just the tail field of B., and require that they're equal.
                     let unsized_a_ty =
-                        tcx.mk_tup_from_iter(a_rest_tys.iter().chain([b_last_ty]).copied());
+                        Ty::new_tup_from_iter(tcx, a_rest_tys.iter().chain([b_last_ty]).copied());
                     ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
 
                     // Similar to ADTs, require that the rest of the fields are equal.
@@ -495,7 +495,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                             .map(ty::Binder::dummy),
                     );
                 let new_a_data = tcx.mk_poly_existential_predicates_from_iter(new_a_data);
-                let new_a_ty = tcx.mk_dynamic(new_a_data, b_region, ty::Dyn);
+                let new_a_ty = Ty::new_dynamic(tcx, new_a_data, b_region, ty::Dyn);
 
                 // We also require that A's lifetime outlives B's lifetime.
                 ecx.eq(goal.param_env, new_a_ty, b_ty)?;
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 250aa79522c..5b875e19996 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -974,7 +974,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             && self.fallback_has_occurred
                         {
                             let predicate = trait_predicate.map_bound(|trait_pred| {
-                                trait_pred.with_self_ty(self.tcx, self.tcx.mk_unit())
+                                trait_pred.with_self_ty(self.tcx, Ty::new_unit(self.tcx))
                             });
                             let unit_obligation = obligation.with(tcx, predicate);
                             if self.predicate_may_hold(&unit_obligation) {
@@ -1625,10 +1625,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     bound_predicate.rebind(data),
                 );
                 let unnormalized_term = match data.term.unpack() {
-                    ty::TermKind::Ty(_) => self
-                        .tcx
-                        .mk_projection(data.projection_ty.def_id, data.projection_ty.substs)
-                        .into(),
+                    ty::TermKind::Ty(_) => Ty::new_projection(
+                        self.tcx,
+                        data.projection_ty.def_id,
+                        data.projection_ty.substs,
+                    )
+                    .into(),
                     ty::TermKind::Const(ct) => ty::Const::new_unevaluated(
                         self.tcx,
                         ty::UnevaluatedConst {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 619a099fcb5..9ac1ba0275c 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -786,7 +786,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 if let Some(steps) =
                     autoderef.into_iter().enumerate().find_map(|(steps, (ty, obligations))| {
                         // Re-add the `&`
-                        let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
+                        let ty = Ty::new_ref(self.tcx, region, TypeAndMut { ty, mutbl });
 
                         // Remapping bound vars here
                         let real_trait_pred_and_ty =
@@ -1298,13 +1298,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {
                 (
                     trait_pred,
-                    self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+                    Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, trait_pred.self_ty()),
                 )
             });
             let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {
                 (
                     trait_pred,
-                    self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+                    Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, trait_pred.self_ty()),
                 )
             });
 
@@ -1465,7 +1465,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
     ) {
         let ty::Ref(_, object_ty, hir::Mutability::Not) = target_ty.kind() else { return; };
         let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else { return; };
-        let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty);
+        let self_ref_ty = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, self_ty);
 
         for predicate in predicates.iter() {
             if !self.predicate_must_hold_modulo_regions(
@@ -1706,8 +1706,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             if let ty::Ref(region, t_type, mutability) = *trait_pred.skip_binder().self_ty().kind()
             {
                 let suggested_ty = match mutability {
-                    hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type),
-                    hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type),
+                    hir::Mutability::Mut => Ty::new_imm_ref(self.tcx, region, t_type),
+                    hir::Mutability::Not => Ty::new_mut_ref(self.tcx, region, t_type),
                 };
 
                 // Remapping bound vars here
@@ -1951,7 +1951,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 ),
             };
 
-            infcx.tcx.mk_fn_ptr(trait_ref.rebind(sig))
+            Ty::new_fn_ptr(infcx.tcx, trait_ref.rebind(sig))
         }
 
         let argument_kind = match expected.skip_binder().self_ty().kind() {
@@ -3347,7 +3347,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
                 // `<T as Future>::Output`
                 let projection_ty = trait_pred.map_bound(|trait_pred| {
-                    self.tcx.mk_projection(
+                    Ty::new_projection(
+                        self.tcx,
                         item_def_id,
                         // Future::Output has no substs
                         [trait_pred.self_ty()],
@@ -3501,7 +3502,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         {
             if let hir::Expr { kind: hir::ExprKind::Block(..), .. } = expr {
                 let expr = expr.peel_blocks();
-                let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc());
+                let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx,));
                 let span = expr.span;
                 if Some(span) != err.span.primary_span() {
                     err.span_label(
@@ -3555,7 +3556,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 {
                     type_diffs = vec![
                         Sorts(ty::error::ExpectedFound {
-                            expected: self.tcx.mk_alias(ty::Projection, where_pred.skip_binder().projection_ty),
+                            expected: Ty::new_alias(self.tcx,ty::Projection, where_pred.skip_binder().projection_ty),
                             found,
                         }),
                     ];
@@ -3646,7 +3647,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
             // Extract `<U as Deref>::Target` assoc type and check that it is `T`
             && let Some(deref_target_did) = tcx.lang_items().deref_target()
-            && let projection = tcx.mk_projection(deref_target_did, tcx.mk_substs(&[ty::GenericArg::from(found_ty)]))
+            && let projection = Ty::new_projection(tcx,deref_target_did, tcx.mk_substs(&[ty::GenericArg::from(found_ty)]))
             && let InferOk { value: deref_target, obligations } = infcx.at(&ObligationCause::dummy(), param_env).normalize(projection)
             && obligations.iter().all(|obligation| infcx.predicate_must_hold_modulo_regions(obligation))
             && infcx.can_eq(param_env, deref_target, target_ty)
@@ -3693,7 +3694,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         let mut assocs = vec![];
         let mut expr = expr;
         let mut prev_ty = self.resolve_vars_if_possible(
-            typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc()),
+            typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
         );
         while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) = expr.kind {
             // Point at every method call in the chain with the resulting type.
@@ -3704,7 +3705,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env);
             assocs.push(assocs_in_this_method);
             prev_ty = self.resolve_vars_if_possible(
-                typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error_misc()),
+                typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
             );
 
             if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
@@ -3722,7 +3723,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 if let hir::Node::Param(param) = parent {
                     // ...and it is a an fn argument.
                     let prev_ty = self.resolve_vars_if_possible(
-                        typeck_results.node_type_opt(param.hir_id).unwrap_or(tcx.ty_error_misc()),
+                        typeck_results.node_type_opt(param.hir_id).unwrap_or(Ty::new_misc_error(tcx,)),
                     );
                     let assocs_in_this_method = self.probe_assoc_types_at_expr(&type_diffs, param.ty_span, prev_ty, param.hir_id, param_env);
                     if assocs_in_this_method.iter().any(|a| a.is_some()) {
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 0adcf336181..c31944c162e 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -509,7 +509,7 @@ fn virtual_call_violation_for_method<'tcx>(
 
             // e.g., `Rc<()>`
             let unit_receiver_ty =
-                receiver_for_self_ty(tcx, receiver_ty, tcx.mk_unit(), method.def_id);
+                receiver_for_self_ty(tcx, receiver_ty, Ty::new_unit(tcx), method.def_id);
 
             match abi_of_ty(unit_receiver_ty) {
                 Some(Abi::Scalar(..)) => (),
@@ -664,7 +664,7 @@ fn object_ty_for_trait<'tcx>(
     );
     debug!(?existential_predicates);
 
-    tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn)
+    Ty::new_dynamic(tcx, existential_predicates, lifetime, ty::Dyn)
 }
 
 /// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
@@ -732,7 +732,7 @@ fn receiver_is_dispatchable<'tcx>(
     // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can
     // replace this with `dyn Trait`
     let unsized_self_ty: Ty<'tcx> =
-        tcx.mk_ty_param(u32::MAX, Symbol::intern("RustaceansAreAwesome"));
+        Ty::new_param(tcx, u32::MAX, Symbol::intern("RustaceansAreAwesome"));
 
     // `Receiver[Self => U]`
     let unsized_receiver_ty =
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 9a8e9d97dda..717b35784d8 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -906,7 +906,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> {
                 let universe = self.universe_for(debruijn);
                 let p = ty::PlaceholderType { universe, bound: bound_ty };
                 self.mapped_types.insert(p, bound_ty);
-                self.infcx.tcx.mk_placeholder(p)
+                Ty::new_placeholder(self.infcx.tcx, p)
             }
             _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
             _ => t,
@@ -1036,7 +1036,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
                         let db = ty::DebruijnIndex::from_usize(
                             self.universe_indices.len() - index + self.current_index.as_usize() - 1,
                         );
-                        self.interner().mk_bound(db, *replace_var)
+                        Ty::new_bound(self.infcx.tcx, db, *replace_var)
                     }
                     None => ty,
                 }
@@ -1440,7 +1440,7 @@ struct Progress<'tcx> {
 
 impl<'tcx> Progress<'tcx> {
     fn error(tcx: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self {
-        Progress { term: tcx.ty_error(guar).into(), obligations: vec![] }
+        Progress { term: Ty::new_error(tcx, guar).into(), obligations: vec![] }
     }
 
     fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self {
@@ -1499,9 +1499,12 @@ fn project<'cx, 'tcx>(
         ProjectionCandidateSet::None => {
             let tcx = selcx.tcx();
             let term = match tcx.def_kind(obligation.predicate.def_id) {
-                DefKind::AssocTy | DefKind::ImplTraitPlaceholder => tcx
-                    .mk_projection(obligation.predicate.def_id, obligation.predicate.substs)
-                    .into(),
+                DefKind::AssocTy | DefKind::ImplTraitPlaceholder => Ty::new_projection(
+                    tcx,
+                    obligation.predicate.def_id,
+                    obligation.predicate.substs,
+                )
+                .into(),
                 DefKind::AssocConst => ty::Const::new_unevaluated(
                     tcx,
                     ty::UnevaluatedConst::new(
@@ -2351,7 +2354,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
                 obligation, poly_cache_entry, e,
             );
             debug!("confirm_param_env_candidate: {}", msg);
-            let err = infcx.tcx.ty_error_with_message(obligation.cause.span, msg);
+            let err = Ty::new_error_with_message(infcx.tcx, obligation.cause.span, msg);
             Progress { term: err.into(), obligations: vec![] }
         }
     }
@@ -2383,7 +2386,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
             "confirm_impl_candidate: no associated type {:?} for {:?}",
             assoc_ty.item.name, obligation.predicate
         );
-        return Progress { term: tcx.ty_error_misc().into(), obligations: nested };
+        return Progress { term: Ty::new_misc_error(tcx).into(), obligations: nested };
     }
     // If we're trying to normalize `<Vec<u32> as X>::A<S>` using
     //`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then:
@@ -2405,7 +2408,8 @@ fn confirm_impl_candidate<'cx, 'tcx>(
         ty.map_bound(|ty| ty.into())
     };
     if !check_substs_compatible(tcx, assoc_ty.item, substs) {
-        let err = tcx.ty_error_with_message(
+        let err = Ty::new_error_with_message(
+            tcx,
             obligation.cause.span,
             "impl item and trait item have different parameters",
         );
@@ -2432,13 +2436,14 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
     // We don't support specialization for RPITITs anyways... yet.
     // Also don't try to project to an RPITIT that has no value
     if !leaf_def.is_final() || !leaf_def.item.defaultness(tcx).has_value() {
-        return Progress { term: tcx.ty_error_misc().into(), obligations };
+        return Progress { term: Ty::new_misc_error(tcx).into(), obligations };
     }
 
     // Use the default `impl Trait` for the trait, e.g., for a default trait body
     if leaf_def.item.container == ty::AssocItemContainer::TraitContainer {
         return Progress {
-            term: tcx.mk_opaque(obligation.predicate.def_id, obligation.predicate.substs).into(),
+            term: Ty::new_opaque(tcx, obligation.predicate.def_id, obligation.predicate.substs)
+                .into(),
             obligations,
         };
     }
@@ -2456,7 +2461,8 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
     );
 
     if !check_substs_compatible(tcx, leaf_def.item, impl_fn_substs) {
-        let err = tcx.ty_error_with_message(
+        let err = Ty::new_error_with_message(
+            tcx,
             obligation.cause.span,
             "impl method and trait method have different parameters",
         );
@@ -2502,7 +2508,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
         cause.clone(),
         obligation.recursion_depth + 1,
         tcx.collect_return_position_impl_trait_in_trait_tys(impl_fn_def_id).map_or_else(
-            |guar| tcx.ty_error(guar),
+            |guar| Ty::new_error(tcx, guar),
             |tys| tys[&obligation.predicate.def_id].subst(tcx, impl_fn_substs),
         ),
         &mut obligations,
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 744c85ed51f..21a223135ed 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -587,7 +587,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 let kind = ty::BoundTyKind::Param(param.def_id, param.name);
                                 let bound_var = ty::BoundVariableKind::Ty(kind);
                                 bound_vars.push(bound_var);
-                                tcx.mk_bound(
+                                Ty::new_bound(
+                                    tcx,
                                     ty::INNERMOST,
                                     ty::BoundTy {
                                         var: ty::BoundVar::from_usize(bound_vars.len() - 1),
@@ -946,7 +947,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             .map(ty::Binder::dummy),
                     );
                 let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(iter);
-                let source_trait = tcx.mk_dynamic(existential_predicates, r_b, repr_a);
+                let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b, repr_a);
 
                 // Require that the traits involved in this upcast are **equal**;
                 // only the **lifetime bound** is changed.
@@ -1039,7 +1040,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             .map(ty::Binder::dummy),
                     );
                 let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(iter);
-                let source_trait = tcx.mk_dynamic(existential_predicates, r_b, dyn_a);
+                let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b, dyn_a);
 
                 // Require that the traits involved in this upcast are **equal**;
                 // only the **lifetime bound** is changed.
@@ -1157,7 +1158,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 let substs = tcx.mk_substs_from_iter(substs_a.iter().enumerate().map(|(i, k)| {
                     if unsizing_params.contains(i as u32) { substs_b[i] } else { k }
                 }));
-                let new_struct = tcx.mk_adt(def, substs);
+                let new_struct = Ty::new_adt(tcx, def, substs);
                 let InferOk { obligations, .. } = self
                     .infcx
                     .at(&obligation.cause, obligation.param_env)
@@ -1188,7 +1189,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // Check that the source tuple with the target's
                 // last element is equal to the target.
                 let new_tuple =
-                    tcx.mk_tup_from_iter(a_mid.iter().copied().chain(iter::once(b_last)));
+                    Ty::new_tup_from_iter(tcx, a_mid.iter().copied().chain(iter::once(b_last)));
                 let InferOk { obligations, .. } = self
                     .infcx
                     .at(&obligation.cause, obligation.param_env)
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 26ed1481228..4a55ceb20a1 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2285,7 +2285,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             | ty::Char => ty::Binder::dummy(Vec::new()),
 
             // Treat this like `struct str([u8]);`
-            ty::Str => ty::Binder::dummy(vec![self.tcx().mk_slice(self.tcx().types.u8)]),
+            ty::Str => ty::Binder::dummy(vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)]),
 
             ty::Placeholder(..)
             | ty::Dynamic(..)
@@ -2435,7 +2435,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                     ),
                 );
                 let value = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
-                let err = self.tcx().ty_error(guar);
+                let err = Ty::new_error(self.tcx(), guar);
                 let value = value.fold_with(&mut BottomUpFolder {
                     tcx: self.tcx(),
                     ty_op: |_| err,
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index b6c64c0196a..302b6cacf2c 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -265,7 +265,7 @@ pub fn closure_trait_ref_and_return_type<'tcx>(
     assert!(!self_ty.has_escaping_bound_vars());
     let arguments_tuple = match tuple_arguments {
         TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
-        TupleArgumentsFlag::Yes => tcx.mk_tup(sig.skip_binder().inputs()),
+        TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()),
     };
     let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple]);
     sig.map_bound(|sig| (trait_ref, sig.output()))
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 0ae6b181519..d81722ce22a 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -952,7 +952,7 @@ pub fn object_region_bounds<'tcx>(
     // Since we don't actually *know* the self type for an object,
     // this "open(err)" serves as a kind of dummy standin -- basically
     // a placeholder type.
-    let open_ty = tcx.mk_fresh_ty(0);
+    let open_ty = Ty::new_fresh(tcx, 0);
 
     let predicates = existential_predicates.iter().filter_map(|predicate| {
         if let ty::ExistentialPredicate::Projection(_) = predicate.skip_binder() {
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 8e2a79dd4d4..55484f5c72e 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -64,7 +64,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                 // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`.
                 sig = sig.map_bound(|mut sig| {
                     let mut inputs_and_output = sig.inputs_and_output.to_vec();
-                    inputs_and_output[0] = tcx.mk_mut_ptr(inputs_and_output[0]);
+                    inputs_and_output[0] = Ty::new_mut_ptr(tcx, inputs_and_output[0]);
                     sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
                     sig
                 });
@@ -106,12 +106,13 @@ fn fn_sig_for_fn_abi<'tcx>(
                 var: ty::BoundVar::from_usize(bound_vars.len() - 1),
                 kind: ty::BoundRegionKind::BrEnv,
             };
-            let env_ty = tcx.mk_mut_ref(ty::Region::new_late_bound(tcx, ty::INNERMOST, br), ty);
+            let env_ty =
+                Ty::new_mut_ref(tcx, ty::Region::new_late_bound(tcx, ty::INNERMOST, br), ty);
 
             let pin_did = tcx.require_lang_item(LangItem::Pin, None);
             let pin_adt_ref = tcx.adt_def(pin_did);
             let pin_substs = tcx.mk_substs(&[env_ty.into()]);
-            let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs);
+            let env_ty = Ty::new_adt(tcx, pin_adt_ref, pin_substs);
 
             let sig = sig.skip_binder();
             // The `FnSig` and the `ret_ty` here is for a generators main
@@ -123,7 +124,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                 let poll_did = tcx.require_lang_item(LangItem::Poll, None);
                 let poll_adt_ref = tcx.adt_def(poll_did);
                 let poll_substs = tcx.mk_substs(&[sig.return_ty.into()]);
-                let ret_ty = tcx.mk_adt(poll_adt_ref, poll_substs);
+                let ret_ty = Ty::new_adt(tcx, poll_adt_ref, poll_substs);
 
                 // We have to replace the `ResumeTy` that is used for type and borrow checking
                 // with `&mut Context<'_>` which is used in codegen.
@@ -137,7 +138,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                         panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty);
                     };
                 }
-                let context_mut_ref = tcx.mk_task_context();
+                let context_mut_ref = Ty::new_task_context(tcx);
 
                 (context_mut_ref, ret_ty)
             } else {
@@ -145,7 +146,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                 let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
                 let state_adt_ref = tcx.adt_def(state_did);
                 let state_substs = tcx.mk_substs(&[sig.yield_ty.into(), sig.return_ty.into()]);
-                let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
+                let ret_ty = Ty::new_adt(tcx, state_adt_ref, state_substs);
 
                 (sig.resume_ty, ret_ty)
             };
@@ -566,7 +567,7 @@ fn make_thin_self_ptr<'tcx>(
     let fat_pointer_ty = if layout.is_unsized() {
         // unsized `self` is passed as a pointer to `self`
         // FIXME (mikeyhew) change this to use &own if it is ever added to the language
-        tcx.mk_mut_ptr(layout.ty)
+        Ty::new_mut_ptr(tcx, layout.ty)
     } else {
         match layout.abi {
             Abi::ScalarPair(..) | Abi::Scalar(..) => (),
@@ -600,7 +601,7 @@ fn make_thin_self_ptr<'tcx>(
     // we now have a type like `*mut RcBox<dyn Trait>`
     // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
     // this is understood as a special case elsewhere in the compiler
-    let unit_ptr_ty = tcx.mk_mut_ptr(tcx.mk_unit());
+    let unit_ptr_ty = Ty::new_mut_ptr(tcx, Ty::new_unit(tcx));
 
     TyAndLayout {
         ty: fat_pointer_ty,
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index 1adaf5f572e..897e7aad48b 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -5,7 +5,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_hir::definitions::DefPathData;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, ImplTraitInTraitData, InternalSubsts, TyCtxt};
+use rustc_middle::ty::{self, ImplTraitInTraitData, InternalSubsts, Ty, TyCtxt};
 use rustc_span::symbol::kw;
 
 pub fn provide(providers: &mut Providers) {
@@ -301,7 +301,8 @@ fn associated_type_for_impl_trait_in_trait(
     trait_assoc_ty.defaultness(tcx.defaultness(fn_def_id));
 
     // Copy type_of of the opaque.
-    trait_assoc_ty.type_of(ty::EarlyBinder::bind(tcx.mk_opaque(
+    trait_assoc_ty.type_of(ty::EarlyBinder::bind(Ty::new_opaque(
+        tcx,
         opaque_ty_def_id.to_def_id(),
         InternalSubsts::identity_for_item(tcx, opaque_ty_def_id),
     )));
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index ac015ddcb49..9ef9120e294 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -159,7 +159,7 @@ fn layout_of_uncached<'tcx>(
                 // fall back to structurally deducing metadata.
                 && !pointee.references_error()
             {
-                let pointee_metadata = tcx.mk_projection(metadata_def_id, [pointee]);
+                let pointee_metadata = Ty::new_projection(tcx,metadata_def_id, [pointee]);
                 let metadata_ty = match tcx.try_normalize_erasing_regions(
                     param_env,
                     pointee_metadata,
@@ -672,7 +672,7 @@ fn generator_layout<'tcx>(
     let promoted_layouts = ineligible_locals
         .iter()
         .map(|local| subst_field(info.field_tys[local].ty))
-        .map(|ty| tcx.mk_maybe_uninit(ty))
+        .map(|ty| Ty::new_maybe_uninit(tcx, ty))
         .map(|ty| Ok(cx.layout_of(ty)?.layout));
     let prefix_layouts = substs
         .as_generator()
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 620db143582..466616cd22b 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -95,7 +95,7 @@ fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness {
 fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> &[Ty<'_>] {
     if let Some(def_id) = def_id.as_local() {
         if matches!(tcx.representability(def_id), ty::Representability::Infinite) {
-            return tcx.mk_type_list(&[tcx.ty_error_misc()]);
+            return tcx.mk_type_list(&[Ty::new_misc_error(tcx)]);
         }
     }
     let def = tcx.adt_def(def_id);
@@ -285,7 +285,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
             let default_ty = if self.tcx.lower_impl_trait_in_trait_to_assoc_ty() {
                 self.tcx.type_of(shifted_alias_ty.def_id).subst(self.tcx, shifted_alias_ty.substs)
             } else {
-                self.tcx.mk_alias(ty::Opaque, shifted_alias_ty)
+                Ty::new_alias(self.tcx,ty::Opaque, shifted_alias_ty)
             };
 
             self.predicates.push(
diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
index 8c3ad24eeed..e8775b08144 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -61,7 +61,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -
             )
         })
         .map_or(false, |assoc_item| {
-            let proj = cx.tcx.mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(ty, []));
+            let proj = Ty::new_projection(cx.tcx,assoc_item.def_id, cx.tcx.mk_substs_trait(ty, []));
             let nty = cx.tcx.normalize_erasing_regions(cx.param_env, proj);
 
             nty.is_bool()
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index f3347e33077..5c5a4cfce88 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -149,7 +149,7 @@ fn is_ref_iterable<'tcx>(
                 let self_ty = if mutbl.is_mut() {
                     self_ty
                 } else {
-                    cx.tcx.mk_ref(region, TypeAndMut { ty, mutbl })
+                    Ty::new_ref(cx.tcx,region, TypeAndMut { ty, mutbl })
                 };
                 if implements_trait(cx, self_ty, trait_id, &[])
                     && let Some(ty) =
@@ -164,7 +164,7 @@ fn is_ref_iterable<'tcx>(
             && !self_ty.is_ref()
         {
             // Attempt to borrow
-            let self_ty = cx.tcx.mk_ref(cx.tcx.lifetimes.re_erased, TypeAndMut {
+            let self_ty = Ty::new_ref(cx.tcx,cx.tcx.lifetimes.re_erased, TypeAndMut {
                 ty: self_ty,
                 mutbl,
             });
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index ac209d01406..8ca7af8107f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -215,7 +215,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty:
         && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, item, [collect_ty])
         && let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions(
             cx.param_env,
-            cx.tcx.mk_projection(into_iter_item_proj.def_id, into_iter_item_proj.substs)
+            Ty::new_projection(cx.tcx,into_iter_item_proj.def_id, into_iter_item_proj.substs)
         )
     {
         iter_item_ty == into_iter_item_ty
@@ -238,7 +238,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -
             .associated_items(iter_trait)
             .find_by_name_and_kind(cx.tcx, Ident::with_dummy_span(Symbol::intern("Item")), AssocKind::Type, iter_trait)
         && let substs = cx.tcx.mk_substs(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))])
-        && let proj_ty = cx.tcx.mk_projection(iter_item.def_id, substs)
+        && let proj_ty = Ty::new_projection(cx.tcx,iter_item.def_id, substs)
         && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty)
     {
         item_ty == EarlyBinder::bind(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id))
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 16ef24bd4e3..6bd5e9e88c8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -270,7 +270,7 @@ fn check_other_call_arg<'tcx>(
         if let Some((n_refs, receiver_ty)) = if n_refs > 0 || is_copy(cx, receiver_ty) {
             Some((n_refs, receiver_ty))
         } else if trait_predicate.def_id() != deref_trait_id {
-            Some((1, cx.tcx.mk_ref(
+            Some((1, Ty::new_ref(cx.tcx,
                 cx.tcx.lifetimes.re_erased,
                 ty::TypeAndMut {
                     ty: receiver_ty,
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index ece10474715..f11d5773d04 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -17,7 +17,7 @@ use rustc_hir_typeck::expr_use_visitor as euv;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::FakeReadCause;
-use rustc_middle::ty::{self, TypeVisitableExt};
+use rustc_middle::ty::{self, TypeVisitableExt, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::kw;
@@ -168,7 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                 (
                     preds.iter().any(|t| cx.tcx.is_diagnostic_item(sym::Borrow, t.def_id())),
                     !preds.is_empty() && {
-                        let ty_empty_region = cx.tcx.mk_imm_ref(cx.tcx.lifetimes.re_erased, ty);
+                        let ty_empty_region = Ty::new_imm_ref(cx.tcx,cx.tcx.lifetimes.re_erased, ty);
                         preds.iter().all(|t| {
                             let ty_params = t.trait_ref.substs.iter().skip(1).collect::<Vec<_>>();
                             implements_trait(cx, ty_empty_region, t.def_id(), &ty_params)
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 866a04466c9..32213718b27 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -389,11 +389,11 @@ impl<'tcx> DerefTy<'tcx> {
     fn ty(&self, cx: &LateContext<'tcx>) -> Ty<'tcx> {
         match *self {
             Self::Str => cx.tcx.types.str_,
-            Self::Path => cx.tcx.mk_adt(
+            Self::Path => Ty::new_adt(cx.tcx,
                 cx.tcx.adt_def(cx.tcx.get_diagnostic_item(sym::Path).unwrap()),
                 List::empty(),
             ),
-            Self::Slice(_, ty) => cx.tcx.mk_slice(ty),
+            Self::Slice(_, ty) => Ty::new_slice(cx.tcx,ty),
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index 2fdd775ad48..c70ce83a9c4 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -7,6 +7,7 @@ use rustc_ast::util::parser::PREC_PREFIX;
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
 use rustc_lint::{LateContext, LateLintPass, Lint};
+use rustc_middle::ty::Ty;
 use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::subst::GenericArg;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -134,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
                 } else if let Some(target_id) = cx.tcx.lang_items().deref_target() {
                     if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(
                         cx.param_env,
-                        cx.tcx.mk_projection(target_id, cx.tcx.mk_substs(&[GenericArg::from(indexed_ty)])),
+                        Ty::new_projection(cx.tcx,target_id, cx.tcx.mk_substs(&[GenericArg::from(indexed_ty)])),
                     ) {
                         if deref_ty == expr_ty {
                             let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
index 31a9b69ca15..857d2ad8258 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(
                 "transmute from a pointer to a pointer",
                 |diag| {
                     if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
-                        let sugg = arg.as_ty(cx.tcx.mk_ptr(*to_ty));
+                        let sugg = arg.as_ty(Ty::new_ptr(cx.tcx,*to_ty));
                         diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified);
                     }
                 },
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
index 426c7253806..ea9ad99618a 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
@@ -64,8 +64,8 @@ pub(super) fn check<'tcx>(
                             };
                             let ty_to_and_mut = ty::TypeAndMut { ty: *ty_to, mutbl: *to_mutbl };
                             let sugg_paren = arg
-                                .as_ty(cx.tcx.mk_ptr(ty_from_and_mut))
-                                .as_ty(cx.tcx.mk_ptr(ty_to_and_mut));
+                                .as_ty(Ty::new_ptr(cx.tcx,ty_from_and_mut))
+                                .as_ty(Ty::new_ptr(cx.tcx,ty_to_and_mut));
                             let sugg = if *to_mutbl == Mutability::Mut {
                                 sugg_paren.mut_addr_deref()
                             } else {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
index 56207fe767c..b6615410e25 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
@@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(
                             let sugg = if *ptr_ty == rty_and_mut {
                                 arg.as_ty(to_ty)
                             } else {
-                                arg.as_ty(cx.tcx.mk_ptr(rty_and_mut)).as_ty(to_ty)
+                                arg.as_ty(Ty::new_ptr(cx.tcx,rty_and_mut)).as_ty(to_ty)
                             };
 
                             diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified);
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 9c39d22c61b..d650cbe0b13 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -1124,7 +1124,7 @@ pub fn make_normalized_projection<'tcx>(
             );
             return None;
         }
-        match tcx.try_normalize_erasing_regions(param_env, tcx.mk_projection(ty.def_id, ty.substs)) {
+        match tcx.try_normalize_erasing_regions(param_env, Ty::new_projection(tcx,ty.def_id, ty.substs)) {
             Ok(ty) => Some(ty),
             Err(e) => {
                 debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}");
@@ -1207,7 +1207,7 @@ pub fn make_normalized_projection_with_regions<'tcx>(
             .infer_ctxt()
             .build()
             .at(&cause, param_env)
-            .query_normalize(tcx.mk_projection(ty.def_id, ty.substs))
+            .query_normalize(Ty::new_projection(tcx,ty.def_id, ty.substs))
         {
             Ok(ty) => Some(ty.value),
             Err(e) => {
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index 29881bbcfca..581327e54f1 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -1008,7 +1008,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         // We have to turn the place into a pointer to use the existing code.
         // (The pointer type does not matter, so we use a raw pointer.)
-        let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?;
+        let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx,return_place.layout.ty))?;
         let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout);
         // Reborrow it. With protection! That is part of the point.
         let new_perm = NewPermission::Uniform {
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index c4fc2fea74c..4c0690c585c 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -509,7 +509,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
         // We have to turn the place into a pointer to use the existing code.
         // (The pointer type does not matter, so we use a raw pointer.)
-        let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?;
+        let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx,return_place.layout.ty))?;
         let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout);
         // Reborrow it. With protection! That is part of the point.
         // FIXME: do we truly want a 2phase borrow here?
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 91e004e0106..56de9c007d0 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -8,6 +8,7 @@ use std::task::Poll;
 use std::thread;
 
 use log::info;
+use rustc_middle::ty::Ty;
 
 use crate::borrow_tracker::RetagFields;
 use crate::diagnostics::report_leaks;
@@ -304,7 +305,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
         for arg in config.args.iter() {
             // Make space for `0` terminator.
             let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap();
-            let arg_type = tcx.mk_array(tcx.types.u8, size);
+            let arg_type = Ty::new_array(tcx,tcx.types.u8, size);
             let arg_place =
                 ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?;
             ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?;
@@ -313,7 +314,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
         }
         // Make an array with all these pointers, in the Miri memory.
         let argvs_layout = ecx.layout_of(
-            tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), u64::try_from(argvs.len()).unwrap()),
+            Ty::new_array(tcx,Ty::new_imm_ptr(tcx,tcx.types.u8), u64::try_from(argvs.len()).unwrap()),
         )?;
         let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?;
         for (idx, arg) in argvs.into_iter().enumerate() {
@@ -332,7 +333,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
             ecx.machine.argc = Some(*argc_place);
 
             let argv_place = ecx.allocate(
-                ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?,
+                ecx.layout_of(Ty::new_imm_ptr(tcx,tcx.types.unit))?,
                 MiriMemoryKind::Machine.into(),
             )?;
             ecx.write_immediate(argv, &argv_place.into())?;
@@ -344,7 +345,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
             // Construct a command string with all the arguments.
             let cmd_utf16: Vec<u16> = args_to_utf16_command_string(config.args.iter());
 
-            let cmd_type = tcx.mk_array(tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap());
+            let cmd_type = Ty::new_array(tcx,tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap());
             let cmd_place =
                 ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?;
             ecx.machine.cmd_line = Some(*cmd_place);
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index bbe5bbee719..5fcf3905199 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -313,10 +313,10 @@ pub struct PrimitiveLayouts<'tcx> {
 impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> {
     fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, &'tcx LayoutError<'tcx>> {
         let tcx = layout_cx.tcx;
-        let mut_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut });
-        let const_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not });
+        let mut_raw_ptr = Ty::new_ptr(tcx,TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut });
+        let const_raw_ptr = Ty::new_ptr(tcx,TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not });
         Ok(Self {
-            unit: layout_cx.layout_of(tcx.mk_unit())?,
+            unit: layout_cx.layout_of(Ty::new_unit(tcx,))?,
             i8: layout_cx.layout_of(tcx.types.i8)?,
             i16: layout_cx.layout_of(tcx.types.i16)?,
             i32: layout_cx.layout_of(tcx.types.i32)?,
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index 323991249d3..eaa66f1f874 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -1,7 +1,7 @@
 use crate::*;
 use rustc_ast::ast::Mutability;
 use rustc_middle::ty::layout::LayoutOf as _;
-use rustc_middle::ty::{self, Instance};
+use rustc_middle::ty::{self, Instance, Ty};
 use rustc_span::{BytePos, Loc, Symbol};
 use rustc_target::{abi::Size, spec::abi::Abi};
 
@@ -71,7 +71,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let len: u64 = ptrs.len().try_into().unwrap();
 
         let ptr_ty = this.machine.layouts.mut_raw_ptr.ty;
-        let array_layout = this.layout_of(tcx.mk_array(ptr_ty, len)).unwrap();
+        let array_layout = this.layout_of(Ty::new_array(tcx.tcx,ptr_ty, len)).unwrap();
 
         match flags {
             // storage for pointers is allocated by miri
diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs
index f50c135435f..3d4967f1f83 100644
--- a/src/tools/miri/src/shims/env.rs
+++ b/src/tools/miri/src/shims/env.rs
@@ -5,6 +5,7 @@ use std::mem;
 
 use rustc_const_eval::interpret::Pointer;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_target::abi::Size;
 
@@ -449,7 +450,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         // Make an array with all these pointers inside Miri.
         let tcx = this.tcx;
         let vars_layout = this.layout_of(
-            tcx.mk_array(this.machine.layouts.mut_raw_ptr.ty, u64::try_from(vars.len()).unwrap()),
+            Ty::new_array(tcx.tcx,this.machine.layouts.mut_raw_ptr.ty, u64::try_from(vars.len()).unwrap()),
         )?;
         let vars_place = this.allocate(vars_layout, MiriMemoryKind::Runtime.into())?;
         for (idx, var) in vars.into_iter().enumerate() {
diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs
index e85ab7a48b3..4cdd54fa21b 100644
--- a/src/tools/miri/src/shims/os_str.rs
+++ b/src/tools/miri/src/shims/os_str.rs
@@ -7,6 +7,7 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt};
 #[cfg(windows)]
 use std::os::windows::ffi::{OsStrExt, OsStringExt};
 
+use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf;
 
 use crate::*;
@@ -140,7 +141,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator.
         let this = self.eval_context_mut();
 
-        let arg_type = this.tcx.mk_array(this.tcx.types.u8, size);
+        let arg_type = Ty::new_array(this.tcx.tcx,this.tcx.types.u8, size);
         let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
         let (written, _) = self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap();
         assert!(written);
@@ -156,7 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator.
         let this = self.eval_context_mut();
 
-        let arg_type = this.tcx.mk_array(this.tcx.types.u16, size);
+        let arg_type = Ty::new_array(this.tcx.tcx,this.tcx.types.u16, size);
         let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
         let (written, _) =
             self.write_os_str_to_wide_str(os_str, arg_place.ptr, size, /*truncate*/ false).unwrap();