|
2 | 2 |
|
3 | 3 | pub(super) mod structural_traits;
|
4 | 4 |
|
| 5 | +use std::ops::ControlFlow; |
| 6 | + |
5 | 7 | use derive_where::derive_where;
|
6 | 8 | use rustc_type_ir::inherent::*;
|
7 | 9 | use rustc_type_ir::lang_items::TraitSolverLangItem;
|
8 | 10 | use rustc_type_ir::{
|
9 |
| - self as ty, Interner, TypeFoldable, TypeVisitableExt as _, TypingMode, Upcast as _, elaborate, |
| 11 | + self as ty, Interner, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt as _, |
| 12 | + TypeVisitor, TypingMode, Upcast as _, elaborate, |
10 | 13 | };
|
11 | 14 | use tracing::{debug, instrument};
|
12 | 15 |
|
13 |
| -use super::has_only_region_constraints; |
14 | 16 | use super::trait_goals::TraitGoalProvenVia;
|
| 17 | +use super::{has_only_region_constraints, inspect}; |
15 | 18 | use crate::delegate::SolverDelegate;
|
16 | 19 | use crate::solve::inspect::ProbeKind;
|
17 | 20 | use crate::solve::{
|
18 | 21 | BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource,
|
19 |
| - MaybeCause, NoSolution, QueryResult, |
| 22 | + MaybeCause, NoSolution, ParamEnvSource, QueryResult, |
20 | 23 | };
|
21 | 24 |
|
22 | 25 | enum AliasBoundKind {
|
|
49 | 52 |
|
50 | 53 | fn trait_def_id(self, cx: I) -> I::DefId;
|
51 | 54 |
|
52 |
| - /// Try equating an assumption predicate against a goal's predicate. If it |
53 |
| - /// holds, then execute the `then` callback, which should do any additional |
54 |
| - /// work, then produce a response (typically by executing |
55 |
| - /// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]). |
56 |
| - fn probe_and_match_goal_against_assumption( |
57 |
| - ecx: &mut EvalCtxt<'_, D>, |
58 |
| - source: CandidateSource<I>, |
59 |
| - goal: Goal<I, Self>, |
60 |
| - assumption: I::Clause, |
61 |
| - then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>, |
62 |
| - ) -> Result<Candidate<I>, NoSolution>; |
63 |
| - |
64 | 55 | /// Consider a clause, which consists of a "assumption" and some "requirements",
|
65 | 56 | /// to satisfy a goal. If the requirements hold, then attempt to satisfy our
|
66 | 57 | /// goal by equating it with the assumption.
|
@@ -119,6 +110,67 @@ where
|
119 | 110 | alias_ty: ty::AliasTy<I>,
|
120 | 111 | ) -> Vec<Candidate<I>>;
|
121 | 112 |
|
| 113 | + fn probe_and_consider_param_env_candidate( |
| 114 | + ecx: &mut EvalCtxt<'_, D>, |
| 115 | + goal: Goal<I, Self>, |
| 116 | + assumption: I::Clause, |
| 117 | + ) -> Result<Candidate<I>, NoSolution> { |
| 118 | + Self::fast_reject_assumption(ecx, goal, assumption)?; |
| 119 | + |
| 120 | + ecx.probe(|candidate: &Result<Candidate<I>, NoSolution>| match candidate { |
| 121 | + Ok(candidate) => inspect::ProbeKind::TraitCandidate { |
| 122 | + source: candidate.source, |
| 123 | + result: Ok(candidate.result), |
| 124 | + }, |
| 125 | + Err(NoSolution) => inspect::ProbeKind::TraitCandidate { |
| 126 | + source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), |
| 127 | + result: Err(NoSolution), |
| 128 | + }, |
| 129 | + }) |
| 130 | + .enter(|ecx| { |
| 131 | + Self::match_assumption(ecx, goal, assumption)?; |
| 132 | + let source = ecx.characterize_param_env_assumption(goal.param_env, assumption)?; |
| 133 | + Ok(Candidate { |
| 134 | + source, |
| 135 | + result: ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)?, |
| 136 | + }) |
| 137 | + }) |
| 138 | + } |
| 139 | + |
| 140 | + /// Try equating an assumption predicate against a goal's predicate. If it |
| 141 | + /// holds, then execute the `then` callback, which should do any additional |
| 142 | + /// work, then produce a response (typically by executing |
| 143 | + /// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]). |
| 144 | + fn probe_and_match_goal_against_assumption( |
| 145 | + ecx: &mut EvalCtxt<'_, D>, |
| 146 | + source: CandidateSource<I>, |
| 147 | + goal: Goal<I, Self>, |
| 148 | + assumption: I::Clause, |
| 149 | + then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>, |
| 150 | + ) -> Result<Candidate<I>, NoSolution> { |
| 151 | + Self::fast_reject_assumption(ecx, goal, assumption)?; |
| 152 | + |
| 153 | + ecx.probe_trait_candidate(source).enter(|ecx| { |
| 154 | + Self::match_assumption(ecx, goal, assumption)?; |
| 155 | + then(ecx) |
| 156 | + }) |
| 157 | + } |
| 158 | + |
| 159 | + /// Try to reject the assumption based off of simple heuristics, such as [`ty::ClauseKind`] |
| 160 | + /// and [`I::DefId`]. |
| 161 | + fn fast_reject_assumption( |
| 162 | + ecx: &mut EvalCtxt<'_, D>, |
| 163 | + goal: Goal<I, Self>, |
| 164 | + assumption: I::Clause, |
| 165 | + ) -> Result<(), NoSolution>; |
| 166 | + |
| 167 | + /// Relate the goal and assumption. |
| 168 | + fn match_assumption( |
| 169 | + ecx: &mut EvalCtxt<'_, D>, |
| 170 | + goal: Goal<I, Self>, |
| 171 | + assumption: I::Clause, |
| 172 | + ) -> Result<(), NoSolution>; |
| 173 | + |
122 | 174 | fn consider_impl_candidate(
|
123 | 175 | ecx: &mut EvalCtxt<'_, D>,
|
124 | 176 | goal: Goal<I, Self>,
|
@@ -500,14 +552,8 @@ where
|
500 | 552 | goal: Goal<I, G>,
|
501 | 553 | candidates: &mut Vec<Candidate<I>>,
|
502 | 554 | ) {
|
503 |
| - for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() { |
504 |
| - candidates.extend(G::probe_and_consider_implied_clause( |
505 |
| - self, |
506 |
| - CandidateSource::ParamEnv(i), |
507 |
| - goal, |
508 |
| - assumption, |
509 |
| - [], |
510 |
| - )); |
| 555 | + for assumption in goal.param_env.caller_bounds().iter() { |
| 556 | + candidates.extend(G::probe_and_consider_param_env_candidate(self, goal, assumption)); |
511 | 557 | }
|
512 | 558 | }
|
513 | 559 |
|
@@ -943,4 +989,76 @@ where
|
943 | 989 | }
|
944 | 990 | }
|
945 | 991 | }
|
| 992 | + |
| 993 | + fn characterize_param_env_assumption( |
| 994 | + &mut self, |
| 995 | + param_env: I::ParamEnv, |
| 996 | + assumption: I::Clause, |
| 997 | + ) -> Result<CandidateSource<I>, NoSolution> { |
| 998 | + // FIXME: |
| 999 | + if assumption.has_bound_vars() { |
| 1000 | + return Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)); |
| 1001 | + } |
| 1002 | + |
| 1003 | + match assumption.visit_with(&mut FindParamInClause { ecx: self, param_env }) { |
| 1004 | + ControlFlow::Break(Err(NoSolution)) => Err(NoSolution), |
| 1005 | + ControlFlow::Break(Ok(())) => Ok(CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)), |
| 1006 | + ControlFlow::Continue(()) => Ok(CandidateSource::ParamEnv(ParamEnvSource::Global)), |
| 1007 | + } |
| 1008 | + } |
| 1009 | +} |
| 1010 | + |
| 1011 | +struct FindParamInClause<'a, 'b, D: SolverDelegate<Interner = I>, I: Interner> { |
| 1012 | + ecx: &'a mut EvalCtxt<'b, D>, |
| 1013 | + param_env: I::ParamEnv, |
| 1014 | +} |
| 1015 | + |
| 1016 | +impl<D, I> TypeVisitor<I> for FindParamInClause<'_, '_, D, I> |
| 1017 | +where |
| 1018 | + D: SolverDelegate<Interner = I>, |
| 1019 | + I: Interner, |
| 1020 | +{ |
| 1021 | + type Result = ControlFlow<Result<(), NoSolution>>; |
| 1022 | + |
| 1023 | + fn visit_binder<T: TypeFoldable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result { |
| 1024 | + self.ecx.enter_forall(t.clone(), |ecx, v| { |
| 1025 | + v.visit_with(&mut FindParamInClause { ecx, param_env: self.param_env }) |
| 1026 | + }) |
| 1027 | + } |
| 1028 | + |
| 1029 | + fn visit_ty(&mut self, ty: I::Ty) -> Self::Result { |
| 1030 | + let Ok(ty) = self.ecx.structurally_normalize_ty(self.param_env, ty) else { |
| 1031 | + return ControlFlow::Break(Err(NoSolution)); |
| 1032 | + }; |
| 1033 | + let ty = self.ecx.eager_resolve(ty); |
| 1034 | + |
| 1035 | + if let ty::Placeholder(_) = ty.kind() { |
| 1036 | + ControlFlow::Break(Ok(())) |
| 1037 | + } else { |
| 1038 | + ty.super_visit_with(self) |
| 1039 | + } |
| 1040 | + } |
| 1041 | + |
| 1042 | + fn visit_const(&mut self, ct: I::Const) -> Self::Result { |
| 1043 | + let Ok(ct) = self.ecx.structurally_normalize_const(self.param_env, ct) else { |
| 1044 | + return ControlFlow::Break(Err(NoSolution)); |
| 1045 | + }; |
| 1046 | + let ct = self.ecx.eager_resolve(ct); |
| 1047 | + |
| 1048 | + if let ty::ConstKind::Placeholder(_) = ct.kind() { |
| 1049 | + ControlFlow::Break(Ok(())) |
| 1050 | + } else { |
| 1051 | + ct.super_visit_with(self) |
| 1052 | + } |
| 1053 | + } |
| 1054 | + |
| 1055 | + fn visit_region(&mut self, r: I::Region) -> Self::Result { |
| 1056 | + match r.kind() { |
| 1057 | + ty::ReStatic | ty::ReError(_) => ControlFlow::Continue(()), |
| 1058 | + ty::ReVar(_) | ty::RePlaceholder(_) => ControlFlow::Break(Ok(())), |
| 1059 | + ty::ReErased | ty::ReEarlyParam(_) | ty::ReLateParam(_) | ty::ReBound(..) => { |
| 1060 | + unreachable!() |
| 1061 | + } |
| 1062 | + } |
| 1063 | + } |
946 | 1064 | }
|
0 commit comments