about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-06-17 07:28:35 +0000
committerbors <bors@rust-lang.org>2024-06-17 07:28:35 +0000
commite23ae72ac7a393961886ea62df065ebb6def7d51 (patch)
tree40a6c9271c8e7a1142654d41fde19a0702dac7d0
parentfd7eefc2753e867053a1c567a7b504ae308e3f85 (diff)
parentff154c7122caa5a56c71e1dfa5e49e87e6f26428 (diff)
downloadrust-e23ae72ac7a393961886ea62df065ebb6def7d51.tar.gz
rust-e23ae72ac7a393961886ea62df065ebb6def7d51.zip
Auto merge of #126492 - compiler-errors:more-uplifting, r=lcnr
More preparation for new trait solver uplifting

Getting closer to being able to uplift the whole solver 🙏

Each commit should be self-justifying.

r? lcnr
-rw-r--r--compiler/rustc_middle/src/arena.rs2
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs49
-rw-r--r--compiler/rustc_middle/src/traits/solve.rs30
-rw-r--r--compiler/rustc_middle/src/ty/context.rs5
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs40
-rw-r--r--compiler/rustc_middle/src/ty/opaque_types.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/lib.rs6
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs66
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs24
-rw-r--r--compiler/rustc_trait_selection/src/solve/select.rs (renamed from compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs)0
-rw-r--r--compiler/rustc_type_ir/src/interner.rs7
-rw-r--r--compiler/rustc_type_ir/src/lib.rs2
-rw-r--r--compiler/rustc_type_ir/src/opaque_ty.rs51
-rw-r--r--compiler/rustc_type_ir/src/solve.rs91
16 files changed, 222 insertions, 163 deletions
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index de786c38326..3d4e5caa9b2 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -110,7 +110,7 @@ macro_rules! arena_types {
                     rustc_hir::def_id::DefId,
                     rustc_middle::ty::EarlyBinder<'tcx, rustc_middle::ty::Ty<'tcx>>
                 >,
-            [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>,
+            [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<rustc_middle::ty::TyCtxt<'tcx>>,
             [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<'tcx>,
             [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap,
             [] stripped_cfg_items: rustc_ast::expand::StrippedCfgItem,
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 202d587f0ad..b4e3fae1b43 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -32,54 +32,7 @@ use std::hash::{Hash, Hasher};
 
 pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache};
 // FIXME: Remove this import and import via `solve::`
-pub use rustc_type_ir::solve::BuiltinImplSource;
-
-/// Depending on the stage of compilation, we want projection to be
-/// more or less conservative.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable, Encodable, Decodable)]
-pub enum Reveal {
-    /// At type-checking time, we refuse to project any associated
-    /// type that is marked `default`. Non-`default` ("final") types
-    /// are always projected. This is necessary in general for
-    /// soundness of specialization. However, we *could* allow
-    /// projections in fully-monomorphic cases. We choose not to,
-    /// because we prefer for `default type` to force the type
-    /// definition to be treated abstractly by any consumers of the
-    /// impl. Concretely, that means that the following example will
-    /// fail to compile:
-    ///
-    /// ```compile_fail,E0308
-    /// #![feature(specialization)]
-    /// trait Assoc {
-    ///     type Output;
-    /// }
-    ///
-    /// impl<T> Assoc for T {
-    ///     default type Output = bool;
-    /// }
-    ///
-    /// fn main() {
-    ///     let x: <() as Assoc>::Output = true;
-    /// }
-    /// ```
-    ///
-    /// We also do not reveal the hidden type of opaque types during
-    /// type-checking.
-    UserFacing,
-
-    /// At codegen time, all monomorphic projections will succeed.
-    /// Also, `impl Trait` is normalized to the concrete type,
-    /// which has to be already collected by type-checking.
-    ///
-    /// NOTE: as `impl Trait`'s concrete type should *never*
-    /// be observable directly by the user, `Reveal::All`
-    /// should not be used by checks which may expose
-    /// type equality or type contents to the user.
-    /// There are some exceptions, e.g., around auto traits and
-    /// transmute-checking, which expose some details, but
-    /// not the whole concrete type of the `impl Trait`.
-    All,
-}
+pub use rustc_type_ir::solve::{BuiltinImplSource, Reveal};
 
 /// The reason why we incurred this obligation; used for error reporting.
 ///
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index 0d9ce402c64..9e979620a44 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -1,10 +1,9 @@
 use rustc_ast_ir::try_visit;
 use rustc_data_structures::intern::Interned;
-use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
+use rustc_macros::HashStable;
 use rustc_type_ir as ir;
 pub use rustc_type_ir::solve::*;
 
-use crate::infer::canonical::QueryRegionConstraints;
 use crate::ty::{
     self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor,
 };
@@ -38,37 +37,18 @@ impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> {
 }
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)]
-pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>);
+pub struct ExternalConstraints<'tcx>(
+    pub(crate) Interned<'tcx, ExternalConstraintsData<TyCtxt<'tcx>>>,
+);
 
 impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> {
-    type Target = ExternalConstraintsData<'tcx>;
+    type Target = ExternalConstraintsData<TyCtxt<'tcx>>;
 
     fn deref(&self) -> &Self::Target {
         &self.0
     }
 }
 
-/// Additional constraints returned on success.
-#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default, TypeVisitable, TypeFoldable)]
-pub struct ExternalConstraintsData<'tcx> {
-    // FIXME: implement this.
-    pub region_constraints: QueryRegionConstraints<'tcx>,
-    pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>,
-    pub normalization_nested_goals: NestedNormalizationGoals<'tcx>,
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default, TypeVisitable, TypeFoldable)]
-pub struct NestedNormalizationGoals<'tcx>(pub Vec<(GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>);
-impl<'tcx> NestedNormalizationGoals<'tcx> {
-    pub fn empty() -> Self {
-        NestedNormalizationGoals(vec![])
-    }
-
-    pub fn is_empty(&self) -> bool {
-        self.0.is_empty()
-    }
-}
-
 // FIXME: Having to clone `region_constraints` for folding feels bad and
 // probably isn't great wrt performance.
 //
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 3651c990c97..e2f15dac019 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -88,6 +88,7 @@ use std::ops::{Bound, Deref};
 #[allow(rustc::usage_of_ty_tykind)]
 impl<'tcx> Interner for TyCtxt<'tcx> {
     type DefId = DefId;
+    type LocalDefId = LocalDefId;
     type AdtDef = ty::AdtDef<'tcx>;
 
     type GenericArgs = ty::GenericArgsRef<'tcx>;
@@ -382,7 +383,7 @@ pub struct CtxtInterners<'tcx> {
     bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
     layout: InternedSet<'tcx, LayoutS<FieldIdx, VariantIdx>>,
     adt_def: InternedSet<'tcx, AdtDefData>,
-    external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>,
+    external_constraints: InternedSet<'tcx, ExternalConstraintsData<TyCtxt<'tcx>>>,
     predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>,
     fields: InternedSet<'tcx, List<FieldIdx>>,
     local_def_ids: InternedSet<'tcx, List<LocalDefId>>,
@@ -2093,7 +2094,7 @@ direct_interners! {
     const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
     layout: pub mk_layout(LayoutS<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>,
     adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,
-    external_constraints: pub mk_external_constraints(ExternalConstraintsData<'tcx>):
+    external_constraints: pub mk_external_constraints(ExternalConstraintsData<TyCtxt<'tcx>>):
         ExternalConstraints -> ExternalConstraints<'tcx>,
     predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData<'tcx>):
         PredefinedOpaques -> PredefinedOpaques<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 5a94a53e175..4e388de6fb8 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -94,6 +94,7 @@ pub use self::context::{
 };
 pub use self::instance::{Instance, InstanceDef, ReifyReason, ShortInstance, UnusedGenericParams};
 pub use self::list::{List, ListWithCachedTypeInfo};
+pub use self::opaque_types::OpaqueTypeKey;
 pub use self::parameterized::ParameterizedOverTcx;
 pub use self::pattern::{Pattern, PatternKind};
 pub use self::predicate::{
@@ -758,45 +759,6 @@ impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
-#[derive(TypeFoldable, TypeVisitable)]
-pub struct OpaqueTypeKey<'tcx> {
-    pub def_id: LocalDefId,
-    pub args: GenericArgsRef<'tcx>,
-}
-
-impl<'tcx> OpaqueTypeKey<'tcx> {
-    pub fn iter_captured_args(
-        self,
-        tcx: TyCtxt<'tcx>,
-    ) -> impl Iterator<Item = (usize, GenericArg<'tcx>)> {
-        std::iter::zip(self.args, tcx.variances_of(self.def_id)).enumerate().filter_map(
-            |(i, (arg, v))| match (arg.unpack(), v) {
-                (_, ty::Invariant) => Some((i, arg)),
-                (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => None,
-                _ => bug!("unexpected opaque type arg variance"),
-            },
-        )
-    }
-
-    pub fn fold_captured_lifetime_args(
-        self,
-        tcx: TyCtxt<'tcx>,
-        mut f: impl FnMut(Region<'tcx>) -> Region<'tcx>,
-    ) -> Self {
-        let Self { def_id, args } = self;
-        let args = std::iter::zip(args, tcx.variances_of(def_id)).map(|(arg, v)| {
-            match (arg.unpack(), v) {
-                (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg,
-                (ty::GenericArgKind::Lifetime(lt), _) => f(lt).into(),
-                _ => arg,
-            }
-        });
-        let args = tcx.mk_args_from_iter(args);
-        Self { def_id, args }
-    }
-}
-
 #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
 pub struct OpaqueHiddenType<'tcx> {
     /// The span of this particular definition of the opaque type. So
diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs
index 52902aadd7c..08b2f9e8920 100644
--- a/compiler/rustc_middle/src/ty/opaque_types.rs
+++ b/compiler/rustc_middle/src/ty/opaque_types.rs
@@ -7,6 +7,8 @@ use rustc_span::def_id::DefId;
 use rustc_span::Span;
 use tracing::{debug, instrument, trace};
 
+pub type OpaqueTypeKey<'tcx> = rustc_type_ir::OpaqueTypeKey<TyCtxt<'tcx>>;
+
 /// Converts generic params of a TypeFoldable from one
 /// item's generics to another. Usually from a function's generics
 /// list to the opaque type's own generics.
diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs
index b913a05095c..144caf36ee5 100644
--- a/compiler/rustc_next_trait_solver/src/lib.rs
+++ b/compiler/rustc_next_trait_solver/src/lib.rs
@@ -1,3 +1,9 @@
+//! Crate containing the implementation of the next-generation trait solver.
+//!
+//! This crate may also contain things that are used by the old trait solver,
+//! but were uplifted in the process of making the new trait solver generic.
+//! So if you got to this crate from the old solver, it's totally normal.
+
 pub mod canonicalizer;
 pub mod resolve;
 pub mod solve;
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index 0e0b9e98339..b5753d60f59 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -135,8 +135,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         // Remove any trivial region constraints once we've resolved regions
         external_constraints
             .region_constraints
-            .outlives
-            .retain(|(outlives, _)| outlives.0.as_region().map_or(true, |re| re != outlives.1));
+            .retain(|outlives| outlives.0.as_region().map_or(true, |re| re != outlives.1));
 
         let canonical = Canonicalizer::canonicalize(
             self.infcx,
@@ -179,8 +178,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     fn compute_external_query_constraints(
         &self,
         certainty: Certainty,
-        normalization_nested_goals: NestedNormalizationGoals<'tcx>,
-    ) -> ExternalConstraintsData<'tcx> {
+        normalization_nested_goals: NestedNormalizationGoals<TyCtxt<'tcx>>,
+    ) -> ExternalConstraintsData<TyCtxt<'tcx>> {
         // We only return region constraints once the certainty is `Yes`. This
         // is necessary as we may drop nested goals on ambiguity, which may result
         // in unconstrained inference variables in the region constraints. It also
@@ -193,30 +192,40 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
             // Cannot use `take_registered_region_obligations` as we may compute the response
             // inside of a `probe` whenever we have multiple choices inside of the solver.
             let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned();
-            let mut region_constraints = self.infcx.with_region_constraints(|region_constraints| {
-                make_query_region_constraints(
-                    self.interner(),
-                    region_obligations.iter().map(|r_o| {
-                        (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())
-                    }),
-                    region_constraints,
-                )
-            });
-
+            let QueryRegionConstraints { outlives, member_constraints } =
+                self.infcx.with_region_constraints(|region_constraints| {
+                    make_query_region_constraints(
+                        self.interner(),
+                        region_obligations.iter().map(|r_o| {
+                            (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())
+                        }),
+                        region_constraints,
+                    )
+                });
+            assert_eq!(member_constraints, vec![]);
             let mut seen = FxHashSet::default();
-            region_constraints.outlives.retain(|outlives| seen.insert(*outlives));
-            region_constraints
+            outlives
+                .into_iter()
+                .filter(|(outlives, _)| seen.insert(*outlives))
+                .map(|(outlives, _origin)| outlives)
+                .collect()
         } else {
             Default::default()
         };
 
-        let mut opaque_types = self.infcx.clone_opaque_types_for_query_response();
-        // Only return opaque type keys for newly-defined opaques
-        opaque_types.retain(|(a, _)| {
-            self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a)
-        });
-
-        ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals }
+        ExternalConstraintsData {
+            region_constraints,
+            opaque_types: self
+                .infcx
+                .clone_opaque_types_for_query_response()
+                .into_iter()
+                // Only return *newly defined* opaque types.
+                .filter(|(a, _)| {
+                    self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a)
+                })
+                .collect(),
+            normalization_nested_goals,
+        }
     }
 
     /// After calling a canonical query, we apply the constraints returned
@@ -232,7 +241,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         param_env: ty::ParamEnv<'tcx>,
         original_values: Vec<ty::GenericArg<'tcx>>,
         response: CanonicalResponse<'tcx>,
-    ) -> (NestedNormalizationGoals<'tcx>, Certainty) {
+    ) -> (NestedNormalizationGoals<TyCtxt<'tcx>>, Certainty) {
         let instantiation = Self::compute_query_response_instantiation_values(
             self.infcx,
             &original_values,
@@ -369,16 +378,17 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
         }
     }
 
-    fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) {
-        for &(ty::OutlivesPredicate(lhs, rhs), _) in &region_constraints.outlives {
+    fn register_region_constraints(
+        &mut self,
+        outlives: &[ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>],
+    ) {
+        for &ty::OutlivesPredicate(lhs, rhs) in outlives {
             match lhs.unpack() {
                 GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs),
                 GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs),
                 GenericArgKind::Const(_) => bug!("const outlives: {lhs:?}: {rhs:?}"),
             }
         }
-
-        assert!(region_constraints.member_constraints.is_empty());
     }
 
     fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)]) {
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index 6b8375b53e8..74938d2bbd7 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -29,11 +29,9 @@ use super::inspect::ProofTreeBuilder;
 use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT};
 use super::{search_graph::SearchGraph, Goal};
 use super::{GoalSource, SolverMode};
-pub use select::InferCtxtSelectExt;
 
 pub(super) mod canonical;
 mod probe;
-mod select;
 
 pub struct EvalCtxt<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner>
 where
@@ -339,7 +337,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
         goal_evaluation_kind: GoalEvaluationKind,
         _source: GoalSource,
         goal: Goal<'tcx, ty::Predicate<'tcx>>,
-    ) -> Result<(NestedNormalizationGoals<'tcx>, bool, Certainty), NoSolution> {
+    ) -> Result<(NestedNormalizationGoals<TyCtxt<'tcx>>, bool, Certainty), NoSolution> {
         let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
         let mut goal_evaluation =
             self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind);
@@ -382,7 +380,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
         param_env: ty::ParamEnv<'tcx>,
         original_values: Vec<ty::GenericArg<'tcx>>,
         response: CanonicalResponse<'tcx>,
-    ) -> (NestedNormalizationGoals<'tcx>, Certainty, bool) {
+    ) -> (NestedNormalizationGoals<TyCtxt<'tcx>>, Certainty, bool) {
         if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty {
             return (NestedNormalizationGoals::empty(), response.value.certainty, false);
         }
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index fdcf4ff11e4..4f1be5cbc85 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -37,12 +37,14 @@ mod normalize;
 mod normalizes_to;
 mod project_goals;
 mod search_graph;
+mod select;
 mod trait_goals;
 
-pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt};
+pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt};
 pub use fulfill::{FulfillmentCtxt, NextSolverError};
 pub(crate) use normalize::deeply_normalize_for_diagnostics;
 pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
+pub use select::InferCtxtSelectExt;
 
 /// How many fixpoint iterations we should attempt inside of the solver before bailing
 /// with overflow.
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index 60a15392e0b..5c5923e9d39 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -10,13 +10,13 @@ use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::solve::inspect::ProbeKind;
 use rustc_infer::traits::solve::MaybeCause;
 use rustc_infer::traits::Reveal;
+use rustc_middle::bug;
 use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
 use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::NormalizesTo;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{TypeVisitableExt, Upcast};
-use rustc_middle::{bug, span_bug};
 use rustc_span::{ErrorGuaranteed, DUMMY_SP};
 
 mod anon_const;
@@ -200,14 +200,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
 
             let error_response = |ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, reason| {
                 let guar = tcx.dcx().span_delayed_bug(tcx.def_span(assoc_def.item.def_id), reason);
-                let error_term = match assoc_def.item.kind {
-                    ty::AssocKind::Const => ty::Const::new_error(tcx, guar).into(),
-                    ty::AssocKind::Type => Ty::new_error(tcx, guar).into(),
-                    // This makes no sense...
-                    ty::AssocKind::Fn => span_bug!(
-                        tcx.def_span(assoc_def.item.def_id),
-                        "cannot project to an associated function"
-                    ),
+                let error_term = match goal.predicate.alias.kind(tcx) {
+                    ty::AliasTermKind::ProjectionTy => Ty::new_error(tcx, guar).into(),
+                    ty::AliasTermKind::ProjectionConst => ty::Const::new_error(tcx, guar).into(),
+                    kind => bug!("expected projection, found {kind:?}"),
                 };
                 ecx.instantiate_normalizes_to_term(goal, error_term);
                 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
@@ -238,9 +234,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
             }
 
             // Finally we construct the actual value of the associated type.
-            let term = match assoc_def.item.kind {
-                ty::AssocKind::Type => tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()),
-                ty::AssocKind::Const => {
+            let term = match goal.predicate.alias.kind(tcx) {
+                ty::AliasTermKind::ProjectionTy => {
+                    tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into())
+                }
+                ty::AliasTermKind::ProjectionConst => {
                     if tcx.features().associated_const_equality {
                         bug!("associated const projection is not supported yet")
                     } else {
@@ -254,7 +252,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                         )
                     }
                 }
-                ty::AssocKind::Fn => unreachable!("we should never project to a fn"),
+                kind => bug!("expected projection, found {kind:?}"),
             };
 
             ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, associated_item_args));
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs
index 257fd263b94..257fd263b94 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/select.rs
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index a2b71e1fc25..11c1f73fef3 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -29,6 +29,7 @@ pub trait Interner:
     + IrPrint<ty::FnSig<Self>>
 {
     type DefId: Copy + Debug + Hash + Eq + TypeFoldable<Self>;
+    type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>;
     type AdtDef: AdtDef<Self>;
 
     type GenericArgs: GenericArgs<Self>;
@@ -103,7 +104,11 @@ pub trait Interner:
     type GenericsOf: GenericsOf<Self>;
     fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf;
 
-    type VariancesOf: Copy + Debug + Deref<Target = [ty::Variance]>;
+    type VariancesOf: Copy
+        + Debug
+        + Deref<Target = [ty::Variance]>
+        // FIXME: This is terrible!
+        + IntoIterator<Item: Deref<Target = ty::Variance>>;
     fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf;
 
     // FIXME: Remove after uplifting `EarlyBinder`
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 4775a0f8cbb..ac9b2808804 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -47,6 +47,7 @@ mod flags;
 mod generic_arg;
 mod infcx;
 mod interner;
+mod opaque_ty;
 mod predicate;
 mod predicate_kind;
 mod region_kind;
@@ -63,6 +64,7 @@ pub use flags::*;
 pub use generic_arg::*;
 pub use infcx::InferCtxtLike;
 pub use interner::*;
+pub use opaque_ty::*;
 pub use predicate::*;
 pub use predicate_kind::*;
 pub use region_kind::*;
diff --git a/compiler/rustc_type_ir/src/opaque_ty.rs b/compiler/rustc_type_ir/src/opaque_ty.rs
new file mode 100644
index 00000000000..60737066597
--- /dev/null
+++ b/compiler/rustc_type_ir/src/opaque_ty.rs
@@ -0,0 +1,51 @@
+use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
+use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
+
+use crate::inherent::*;
+use crate::{self as ty, Interner};
+
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Debug(bound = ""),
+    Copy(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
+pub struct OpaqueTypeKey<I: Interner> {
+    pub def_id: I::LocalDefId,
+    pub args: I::GenericArgs,
+}
+
+impl<I: Interner> OpaqueTypeKey<I> {
+    pub fn iter_captured_args(self, tcx: I) -> impl Iterator<Item = (usize, I::GenericArg)> {
+        let variances = tcx.variances_of(self.def_id.into());
+        std::iter::zip(self.args, variances.into_iter()).enumerate().filter_map(|(i, (arg, v))| {
+            match (arg.kind(), *v) {
+                (_, ty::Invariant) => Some((i, arg)),
+                (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => None,
+                _ => panic!("unexpected opaque type arg variance"),
+            }
+        })
+    }
+
+    pub fn fold_captured_lifetime_args(
+        self,
+        tcx: I,
+        mut f: impl FnMut(I::Region) -> I::Region,
+    ) -> Self {
+        let Self { def_id, args } = self;
+        let variances = tcx.variances_of(def_id.into());
+        let args =
+            std::iter::zip(args, variances.into_iter()).map(|(arg, v)| match (arg.kind(), *v) {
+                (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg,
+                (ty::GenericArgKind::Lifetime(lt), _) => f(lt).into(),
+                _ => arg,
+            });
+        let args = tcx.mk_args_from_iter(args);
+        Self { def_id, args }
+    }
+}
diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs
index 6a89a8a4cc3..99d2fa74494 100644
--- a/compiler/rustc_type_ir/src/solve.rs
+++ b/compiler/rustc_type_ir/src/solve.rs
@@ -7,7 +7,55 @@ use std::hash::Hash;
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 
-use crate::{Canonical, CanonicalVarValues, Interner, Upcast};
+use crate::{self as ty, Canonical, CanonicalVarValues, Interner, Upcast};
+
+/// Depending on the stage of compilation, we want projection to be
+/// more or less conservative.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub enum Reveal {
+    /// At type-checking time, we refuse to project any associated
+    /// type that is marked `default`. Non-`default` ("final") types
+    /// are always projected. This is necessary in general for
+    /// soundness of specialization. However, we *could* allow
+    /// projections in fully-monomorphic cases. We choose not to,
+    /// because we prefer for `default type` to force the type
+    /// definition to be treated abstractly by any consumers of the
+    /// impl. Concretely, that means that the following example will
+    /// fail to compile:
+    ///
+    /// ```compile_fail,E0308
+    /// #![feature(specialization)]
+    /// trait Assoc {
+    ///     type Output;
+    /// }
+    ///
+    /// impl<T> Assoc for T {
+    ///     default type Output = bool;
+    /// }
+    ///
+    /// fn main() {
+    ///     let x: <() as Assoc>::Output = true;
+    /// }
+    /// ```
+    ///
+    /// We also do not reveal the hidden type of opaque types during
+    /// type-checking.
+    UserFacing,
+
+    /// At codegen time, all monomorphic projections will succeed.
+    /// Also, `impl Trait` is normalized to the concrete type,
+    /// which has to be already collected by type-checking.
+    ///
+    /// NOTE: as `impl Trait`'s concrete type should *never*
+    /// be observable directly by the user, `Reveal::All`
+    /// should not be used by checks which may expose
+    /// type equality or type contents to the user.
+    /// There are some exceptions, e.g., around auto traits and
+    /// transmute-checking, which expose some details, but
+    /// not the whole concrete type of the `impl Trait`.
+    All,
+}
 
 pub type CanonicalInput<I, T = <I as Interner>::Predicate> = Canonical<I, QueryInput<I, T>>;
 pub type CanonicalResponse<I> = Canonical<I, Response<I>>;
@@ -206,6 +254,47 @@ pub struct Response<I: Interner> {
     pub external_constraints: I::ExternalConstraints,
 }
 
+/// Additional constraints returned on success.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Debug(bound = ""),
+    Default(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+pub struct ExternalConstraintsData<I: Interner> {
+    pub region_constraints: Vec<ty::OutlivesPredicate<I, I::GenericArg>>,
+    pub opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>,
+    pub normalization_nested_goals: NestedNormalizationGoals<I>,
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Debug(bound = ""),
+    Default(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+pub struct NestedNormalizationGoals<I: Interner>(pub Vec<(GoalSource, Goal<I, I::Predicate>)>);
+
+impl<I: Interner> NestedNormalizationGoals<I> {
+    pub fn empty() -> Self {
+        NestedNormalizationGoals(vec![])
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+}
+
 #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
 #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
 pub enum Certainty {