]>
Commit | Line | Data |
---|---|---|
9ffffee4 FG |
1 | use rustc_hir::def_id::DefId; |
2 | use rustc_infer::infer::at::ToTrace; | |
3 | use rustc_infer::infer::canonical::CanonicalVarValues; | |
4 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; | |
5 | use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; | |
6 | use rustc_infer::traits::query::NoSolution; | |
7 | use rustc_infer::traits::ObligationCause; | |
8 | use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; | |
9 | use rustc_middle::ty::{ | |
10 | self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, | |
11 | TypeVisitor, | |
12 | }; | |
13 | use rustc_span::DUMMY_SP; | |
14 | use std::ops::ControlFlow; | |
15 | ||
16 | use super::search_graph::SearchGraph; | |
17 | use super::Goal; | |
18 | ||
19 | pub 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 | ||
41 | impl<'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 | } |