about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-05-09 18:56:43 +0000
committerMichael Goulet <michael@errs.io>2023-05-25 03:19:15 +0000
commit4d80b8090c30980c03ff4bb6f47a7560ffaa68a4 (patch)
treed45cf4788222a3542ea503f8083f516ecbb04855
parent7664dfe4331265d0b2b1ffb89c92d443886bec0b (diff)
downloadrust-4d80b8090c30980c03ff4bb6f47a7560ffaa68a4.tar.gz
rust-4d80b8090c30980c03ff4bb6f47a7560ffaa68a4.zip
Pull out logic from #111131, plus some new logic in EvalCtxt::normalize_opaque_type
Co-authored-by: lcnr <rust@lcnr.de>
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs5
-rw-r--r--compiler/rustc_infer/src/infer/equate.rs3
-rw-r--r--compiler/rustc_infer/src/infer/lattice.rs5
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs22
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs45
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs3
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs14
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/opaques.rs44
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs6
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs2
13 files changed, 122 insertions, 43 deletions
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 79fc02c6c79..b6b935de68c 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -113,10 +113,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 bug!()
             }
 
-            (_, ty::Alias(AliasKind::Projection | AliasKind::Inherent, _))
-            | (ty::Alias(AliasKind::Projection | AliasKind::Inherent, _), _)
-                if self.tcx.trait_solver_next() =>
-            {
+            (_, ty::Alias(..)) | (ty::Alias(..), _) if self.tcx.trait_solver_next() => {
                 relation.register_type_relate_obligation(a, b);
                 Ok(a)
             }
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index 793505e4ab2..42dfe4f6bb8 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -104,7 +104,8 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
             (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
             | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
                 if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
-                    && def_id.is_local() =>
+                    && def_id.is_local()
+                    && !self.tcx().trait_solver_next() =>
             {
                 self.fields.obligations.extend(
                     infcx
diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs
index 7f4c141b97a..7190d33d299 100644
--- a/compiler/rustc_infer/src/infer/lattice.rs
+++ b/compiler/rustc_infer/src/infer/lattice.rs
@@ -108,9 +108,12 @@ where
             &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
             &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
         ) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b),
+
         (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
         | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
-            if this.define_opaque_types() == DefineOpaqueTypes::Yes && def_id.is_local() =>
+            if this.define_opaque_types() == DefineOpaqueTypes::Yes
+                && def_id.is_local()
+                && !this.tcx().trait_solver_next() =>
         {
             this.register_obligations(
                 infcx
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 4ae6af5f5be..d3fd01b9642 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -491,16 +491,22 @@ where
             (
                 &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
                 &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
-            ) if a_def_id == b_def_id => infcx.super_combine_tys(self, a, b).or_else(|err| {
-                self.tcx().sess.delay_span_bug(
-                    self.delegate.span(),
-                    "failure to relate an opaque to itself should result in an error later on",
-                );
-                if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
-            }),
+            ) if a_def_id == b_def_id || infcx.tcx.trait_solver_next() => {
+                infcx.super_combine_tys(self, a, b).or_else(|err| {
+                    // This behavior is only there for the old solver, the new solver
+                    // shouldn't ever fail. Instead, it unconditionally emits an
+                    // alias-relate goal.
+                    assert!(!self.tcx().trait_solver_next());
+                    self.tcx().sess.delay_span_bug(
+                        self.delegate.span(),
+                        "failure to relate an opaque to itself should result in an error later on",
+                    );
+                    if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
+                })
+            }
             (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
             | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
-                if def_id.is_local() =>
+                if def_id.is_local() && !self.tcx().trait_solver_next() =>
             {
                 self.relate_opaques(a, b)
             }
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 213b3f0fe0e..21df3291f36 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -2,7 +2,7 @@ use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use super::{DefineOpaqueTypes, InferResult};
 use crate::errors::OpaqueHiddenTypeDiag;
 use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
-use crate::traits;
+use crate::traits::{self, PredicateObligation};
 use hir::def_id::{DefId, LocalDefId};
 use hir::OpaqueTyOrigin;
 use rustc_data_structures::fx::FxIndexMap;
@@ -48,9 +48,15 @@ impl<'tcx> InferCtxt<'tcx> {
         span: Span,
         param_env: ty::ParamEnv<'tcx>,
     ) -> InferOk<'tcx, T> {
+        // We handle opaque types differently in the new solver.
+        if self.tcx.trait_solver_next() {
+            return InferOk { value, obligations: vec![] };
+        }
+
         if !value.has_opaque_types() {
             return InferOk { value, obligations: vec![] };
         }
+
         let mut obligations = vec![];
         let replace_opaque_type = |def_id: DefId| {
             def_id.as_local().is_some_and(|def_id| self.opaque_type_origin(def_id).is_some())
@@ -521,9 +527,6 @@ impl<'tcx> InferCtxt<'tcx> {
         origin: hir::OpaqueTyOrigin,
         a_is_expected: bool,
     ) -> InferResult<'tcx, ()> {
-        let tcx = self.tcx;
-        let OpaqueTypeKey { def_id, substs } = opaque_type_key;
-
         // Ideally, we'd get the span where *this specific `ty` came
         // from*, but right now we just use the span from the overall
         // value being folded. In simple cases like `-> impl Foo`,
@@ -531,7 +534,7 @@ impl<'tcx> InferCtxt<'tcx> {
         // Foo, impl Bar)`.
         let span = cause.span;
         let prev = self.inner.borrow_mut().opaque_types().register(
-            OpaqueTypeKey { def_id, substs },
+            opaque_type_key,
             OpaqueHiddenType { ty: hidden_ty, span },
             origin,
         );
@@ -543,6 +546,26 @@ impl<'tcx> InferCtxt<'tcx> {
             Vec::new()
         };
 
+        self.add_item_bounds_for_hidden_type(
+            opaque_type_key,
+            cause,
+            param_env,
+            hidden_ty,
+            &mut obligations,
+        );
+
+        Ok(InferOk { value: (), obligations })
+    }
+
+    pub fn add_item_bounds_for_hidden_type(
+        &self,
+        OpaqueTypeKey { def_id, substs }: OpaqueTypeKey<'tcx>,
+        cause: ObligationCause<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        hidden_ty: Ty<'tcx>,
+        obligations: &mut Vec<PredicateObligation<'tcx>>,
+    ) {
+        let tcx = self.tcx;
         let item_bounds = tcx.explicit_item_bounds(def_id);
 
         for (predicate, _) in item_bounds.subst_iter_copied(tcx, substs) {
@@ -555,14 +578,15 @@ impl<'tcx> InferCtxt<'tcx> {
                     // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
                     ty::Alias(ty::Projection, projection_ty)
                         if !projection_ty.has_escaping_bound_vars()
-                            && !tcx.is_impl_trait_in_trait(projection_ty.def_id) =>
+                            && !tcx.is_impl_trait_in_trait(projection_ty.def_id)
+                            && !tcx.trait_solver_next() =>
                     {
                         self.infer_projection(
                             param_env,
                             projection_ty,
                             cause.clone(),
                             0,
-                            &mut obligations,
+                            obligations,
                         )
                     }
                     // Replace all other mentions of the same opaque type with the hidden type,
@@ -588,10 +612,10 @@ impl<'tcx> InferCtxt<'tcx> {
                 predicate.kind().skip_binder()
             {
                 if projection.term.references_error() {
-                    // No point on adding these obligations since there's a type error involved.
-                    return Ok(InferOk { value: (), obligations: vec![] });
+                    // No point on adding any obligations since there's a type error involved.
+                    obligations.clear();
+                    return;
                 }
-                trace!("{:#?}", projection.term);
             }
             // Require that the predicate holds for the concrete type.
             debug!(?predicate);
@@ -602,7 +626,6 @@ impl<'tcx> InferCtxt<'tcx> {
                 predicate,
             ));
         }
-        Ok(InferOk { value: (), obligations })
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index e0f29a8de8f..ceafafb5582 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -131,7 +131,8 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
             (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
             | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
                 if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
-                    && def_id.is_local() =>
+                    && def_id.is_local()
+                    && !self.tcx().trait_solver_next() =>
             {
                 self.fields.obligations.extend(
                     infcx
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index c51548501ef..73f435d4840 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -996,17 +996,11 @@ impl<'tcx> Term<'tcx> {
         }
     }
 
-    /// This function returns the inner `AliasTy` if this term is a projection.
-    ///
-    /// FIXME: rename `AliasTy` to `AliasTerm` and make sure we correctly
-    /// deal with constants.
-    pub fn to_projection_term(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> {
+    /// This function returns the inner `AliasTy` for a `ty::Alias` or `ConstKind::Unevaluated`.
+    pub fn to_alias_ty(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> {
         match self.unpack() {
-            TermKind::Ty(ty) => match ty.kind() {
-                ty::Alias(kind, alias_ty) => match kind {
-                    AliasKind::Projection | AliasKind::Inherent => Some(*alias_ty),
-                    AliasKind::Opaque => None,
-                },
+            TermKind::Ty(ty) => match *ty.kind() {
+                ty::Alias(_kind, alias_ty) => Some(alias_ty),
                 _ => None,
             },
             TermKind::Const(ct) => match ct.kind() {
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 32bd10f0beb..4a403196c7e 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -133,12 +133,14 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
                                 | ty::PredicateKind::ObjectSafe(_)
                                 | ty::PredicateKind::ClosureKind(_, _, _)
                                 | ty::PredicateKind::ConstEvaluatable(_)
-                                | ty::PredicateKind::TypeWellFormedFromEnv(_)
                                 | ty::PredicateKind::Ambiguous => {
                                     FulfillmentErrorCode::CodeSelectionError(
                                         SelectionError::Unimplemented,
                                     )
                                 }
+                                ty::PredicateKind::TypeWellFormedFromEnv(_) => {
+                                    bug!("unexpected goal: {goal:?}")
+                                }
                             },
                             root_obligation: obligation,
                         });
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index d94679fef28..1427268f829 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -24,6 +24,7 @@ mod assembly;
 mod canonicalize;
 mod eval_ctxt;
 mod fulfill;
+mod opaques;
 mod project_goals;
 mod search_graph;
 mod trait_goals;
@@ -212,7 +213,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             );
         }
 
-        match (lhs.to_projection_term(tcx), rhs.to_projection_term(tcx)) {
+        match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) {
             (None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"),
 
             // RHS is not a projection, only way this is true is if LHS normalizes-to RHS
diff --git a/compiler/rustc_trait_selection/src/solve/opaques.rs b/compiler/rustc_trait_selection/src/solve/opaques.rs
new file mode 100644
index 00000000000..1a770459338
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/solve/opaques.rs
@@ -0,0 +1,44 @@
+use rustc_infer::infer::InferOk;
+use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
+use rustc_middle::traits::{ObligationCause, Reveal};
+use rustc_middle::ty::ProjectionPredicate;
+
+use super::{EvalCtxt, SolverMode};
+
+impl<'tcx> EvalCtxt<'_, 'tcx> {
+    pub(super) fn normalize_opaque_type(
+        &mut self,
+        goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
+    ) -> QueryResult<'tcx> {
+        let tcx = self.tcx();
+        let opaque_ty = goal.predicate.projection_ty;
+        let expected = goal.predicate.term.ty().expect("no such thing as an opaque const");
+
+        match goal.param_env.reveal() {
+            Reveal::UserFacing => match self.solver_mode() {
+                SolverMode::Normal => self.probe(|ecx| {
+                    // FIXME: Check that the usage is "defining" (all free params), otherwise bail.
+                    // FIXME: This should probably just check the anchor directly
+                    let InferOk { value: (), obligations } = self.infcx.handle_opaque_type(
+                        expected,
+                        tcx.mk_opaque(opaque_ty.def_id, opaque_ty.substs),
+                        true,
+                        &ObligationCause::dummy(),
+                        goal.param_env,
+                    )?;
+                    // FIXME: Need to fold these to replace the opaque ty with the expected ty.
+                    ecx.add_goals(obligations.into_iter().map(Into::into));
+                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+                }),
+                SolverMode::Coherence => {
+                    self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+                }
+            },
+            Reveal::All => self.probe(|ecx| {
+                let actual = tcx.type_of(opaque_ty.def_id).subst(tcx, opaque_ty.substs);
+                ecx.eq(goal.param_env, expected, actual)?;
+                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+            }),
+        }
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index d3228074421..248b750b3bd 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -30,8 +30,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         // `U` and equate it with `u32`. This means that we don't need a separate
         // projection cache in the solver.
         if self.term_is_fully_unconstrained(goal) {
-            let candidates = self.assemble_and_evaluate_candidates(goal);
-            self.merge_candidates(candidates)
+            match goal.predicate.projection_ty.kind(self.tcx()) {
+                ty::AliasKind::Projection => {
+                    let candidates = self.assemble_and_evaluate_candidates(goal);
+                    self.merge_candidates(candidates)
+                }
+                ty::AliasKind::Opaque => self.normalize_opaque_type(goal),
+            }
         } else {
             self.set_normalizes_to_hack_goal(goal);
             self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 183c2401fc3..62d2aad5277 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -834,8 +834,10 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 | ty::PredicateKind::Subtype(..)
                 // FIXME(generic_const_exprs): you can absolutely add this as a where clauses
                 | ty::PredicateKind::ConstEvaluatable(..)
-                | ty::PredicateKind::Coerce(..)
-                | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
+                | ty::PredicateKind::Coerce(..) => {}
+                ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+                    bug!("predicate should only exist in the environment: {bound_predicate:?}")
+                }
                 ty::PredicateKind::Ambiguous => return false,
             };
         }
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 2f9e480d8bd..e447ab94f64 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -679,7 +679,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
             | ty::PredicateKind::ConstEquate(..)
             | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
-                bug!("unexpected predicate {}", &self)
+                bug!("unexpected predicate {self}")
             }
         };
         value.map(|value| chalk_ir::Binders::new(binders, value))