]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / solve / eval_ctxt.rs
CommitLineData
9ffffee4
FG
1use rustc_hir::def_id::DefId;
2use rustc_infer::infer::at::ToTrace;
3use rustc_infer::infer::canonical::CanonicalVarValues;
4use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
5use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
6use rustc_infer::traits::query::NoSolution;
7use rustc_infer::traits::ObligationCause;
8use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
9use rustc_middle::ty::{
10 self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
11 TypeVisitor,
12};
13use rustc_span::DUMMY_SP;
14use std::ops::ControlFlow;
15
16use super::search_graph::SearchGraph;
17use super::Goal;
18
19pub struct EvalCtxt<'a, 'tcx> {
20 // FIXME: should be private.
21 pub(super) infcx: &'a InferCtxt<'tcx>,
22 pub(super) var_values: CanonicalVarValues<'tcx>,
23 /// The highest universe index nameable by the caller.
24 ///
25 /// When we enter a new binder inside of the query we create new universes
26 /// which the caller cannot name. We have to be careful with variables from
27 /// these new universes when creating the query response.
28 ///
29 /// Both because these new universes can prevent us from reaching a fixpoint
30 /// if we have a coinductive cycle and because that's the only way we can return
31 /// new placeholders to the caller.
32 pub(super) max_input_universe: ty::UniverseIndex,
33
34 pub(super) search_graph: &'a mut SearchGraph<'tcx>,
35
36 /// This field is used by a debug assertion in [`EvalCtxt::evaluate_goal`],
37 /// see the comment in that method for more details.
38 pub in_projection_eq_hack: bool,
39}
40
41impl<'tcx> EvalCtxt<'_, 'tcx> {
42 pub(super) fn probe<T>(&mut self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T {
43 self.infcx.probe(|_| f(self))
44 }
45
46 pub(super) fn tcx(&self) -> TyCtxt<'tcx> {
47 self.infcx.tcx
48 }
49
50 pub(super) fn next_ty_infer(&self) -> Ty<'tcx> {
51 self.infcx.next_ty_var(TypeVariableOrigin {
52 kind: TypeVariableOriginKind::MiscVariable,
53 span: DUMMY_SP,
54 })
55 }
56
57 pub(super) fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx> {
58 self.infcx.next_const_var(
59 ty,
60 ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span: DUMMY_SP },
61 )
62 }
63
64 /// Is the projection predicate is of the form `exists<T> <Ty as Trait>::Assoc = T`.
65 ///
66 /// This is the case if the `term` is an inference variable in the innermost universe
67 /// and does not occur in any other part of the predicate.
68 pub(super) fn term_is_fully_unconstrained(
69 &self,
70 goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
71 ) -> bool {
72 let term_is_infer = match goal.predicate.term.unpack() {
73 ty::TermKind::Ty(ty) => {
74 if let &ty::Infer(ty::TyVar(vid)) = ty.kind() {
75 match self.infcx.probe_ty_var(vid) {
76 Ok(value) => bug!("resolved var in query: {goal:?} {value:?}"),
77 Err(universe) => universe == self.universe(),
78 }
79 } else {
80 false
81 }
82 }
83 ty::TermKind::Const(ct) => {
84 if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() {
85 match self.infcx.probe_const_var(vid) {
86 Ok(value) => bug!("resolved var in query: {goal:?} {value:?}"),
87 Err(universe) => universe == self.universe(),
88 }
89 } else {
90 false
91 }
92 }
93 };
94
95 // Guard against `<T as Trait<?0>>::Assoc = ?0>`.
96 struct ContainsTerm<'tcx> {
97 term: ty::Term<'tcx>,
98 }
99 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ContainsTerm<'tcx> {
100 type BreakTy = ();
101 fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
102 if t.needs_infer() {
103 if ty::Term::from(t) == self.term {
104 ControlFlow::Break(())
105 } else {
106 t.super_visit_with(self)
107 }
108 } else {
109 ControlFlow::Continue(())
110 }
111 }
112
113 fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
114 if c.needs_infer() {
115 if ty::Term::from(c) == self.term {
116 ControlFlow::Break(())
117 } else {
118 c.super_visit_with(self)
119 }
120 } else {
121 ControlFlow::Continue(())
122 }
123 }
124 }
125
126 let mut visitor = ContainsTerm { term: goal.predicate.term };
127
128 term_is_infer
129 && goal.predicate.projection_ty.visit_with(&mut visitor).is_continue()
130 && goal.param_env.visit_with(&mut visitor).is_continue()
131 }
132
133 #[instrument(level = "debug", skip(self, param_env), ret)]
134 pub(super) fn eq<T: ToTrace<'tcx>>(
135 &self,
136 param_env: ty::ParamEnv<'tcx>,
137 lhs: T,
138 rhs: T,
139 ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
140 self.infcx
141 .at(&ObligationCause::dummy(), param_env)
142 .eq(lhs, rhs)
143 .map(|InferOk { value: (), obligations }| {
144 obligations.into_iter().map(|o| o.into()).collect()
145 })
146 .map_err(|e| {
147 debug!(?e, "failed to equate");
148 NoSolution
149 })
150 }
151
152 pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<TyCtxt<'tcx>> + Copy>(
153 &self,
154 value: ty::Binder<'tcx, T>,
155 ) -> T {
156 self.infcx.instantiate_binder_with_fresh_vars(
157 DUMMY_SP,
158 LateBoundRegionConversionTime::HigherRankedType,
159 value,
160 )
161 }
162
163 pub(super) fn instantiate_binder_with_placeholders<T: TypeFoldable<TyCtxt<'tcx>> + Copy>(
164 &self,
165 value: ty::Binder<'tcx, T>,
166 ) -> T {
167 self.infcx.instantiate_binder_with_placeholders(value)
168 }
169
170 pub(super) fn resolve_vars_if_possible<T>(&self, value: T) -> T
171 where
172 T: TypeFoldable<TyCtxt<'tcx>>,
173 {
174 self.infcx.resolve_vars_if_possible(value)
175 }
176
177 pub(super) fn fresh_substs_for_item(&self, def_id: DefId) -> ty::SubstsRef<'tcx> {
178 self.infcx.fresh_substs_for_item(DUMMY_SP, def_id)
179 }
180
181 pub(super) fn universe(&self) -> ty::UniverseIndex {
182 self.infcx.universe()
183 }
184}