rustc_next_trait_solver/solve/
effect_goals.rs1use rustc_type_ir::fast_reject::DeepRejectCtxt;
5use rustc_type_ir::inherent::*;
6use rustc_type_ir::lang_items::SolverTraitLangItem;
7use rustc_type_ir::solve::SizedTraitKind;
8use rustc_type_ir::solve::inspect::ProbeKind;
9use rustc_type_ir::{self as ty, Interner, TypingMode, elaborate};
10use tracing::instrument;
11
12use super::assembly::{Candidate, structural_traits};
13use crate::delegate::SolverDelegate;
14use crate::solve::{
15 BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution,
16 QueryResult, assembly,
17};
18
19impl<D, I> assembly::GoalKind<D> for ty::HostEffectPredicate<I>
20where
21 D: SolverDelegate<Interner = I>,
22 I: Interner,
23{
24 fn self_ty(self) -> I::Ty {
25 self.self_ty()
26 }
27
28 fn trait_ref(self, _: I) -> ty::TraitRef<I> {
29 self.trait_ref
30 }
31
32 fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self {
33 self.with_replaced_self_ty(cx, self_ty)
34 }
35
36 fn trait_def_id(self, _: I) -> I::TraitId {
37 self.def_id()
38 }
39
40 fn fast_reject_assumption(
41 ecx: &mut EvalCtxt<'_, D>,
42 goal: Goal<I, Self>,
43 assumption: I::Clause,
44 ) -> Result<(), NoSolution> {
45 if let Some(host_clause) = assumption.as_host_effect_clause()
46 && host_clause.def_id() == goal.predicate.def_id()
47 && host_clause.constness().satisfies(goal.predicate.constness)
48 && DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
49 goal.predicate.trait_ref.args,
50 host_clause.skip_binder().trait_ref.args,
51 )
52 {
53 Ok(())
54 } else {
55 Err(NoSolution)
56 }
57 }
58
59 fn match_assumption(
60 ecx: &mut EvalCtxt<'_, D>,
61 goal: Goal<I, Self>,
62 assumption: I::Clause,
63 then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
64 ) -> QueryResult<I> {
65 let host_clause = assumption.as_host_effect_clause().unwrap();
66
67 let assumption_trait_pred = ecx.instantiate_binder_with_infer(host_clause);
68 ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
69
70 then(ecx)
71 }
72
73 fn consider_additional_alias_assumptions(
80 ecx: &mut EvalCtxt<'_, D>,
81 goal: Goal<I, Self>,
82 alias_ty: ty::AliasTy<I>,
83 ) -> Vec<Candidate<I>> {
84 let cx = ecx.cx();
85 let mut candidates = vec![];
86
87 if !ecx.cx().alias_has_const_conditions(alias_ty.def_id) {
88 return vec![];
89 }
90
91 for clause in elaborate::elaborate(
92 cx,
93 cx.explicit_implied_const_bounds(alias_ty.def_id)
94 .iter_instantiated(cx, alias_ty.args)
95 .map(|trait_ref| trait_ref.to_host_effect_clause(cx, goal.predicate.constness)),
96 ) {
97 candidates.extend(Self::probe_and_match_goal_against_assumption(
98 ecx,
99 CandidateSource::AliasBound,
100 goal,
101 clause,
102 |ecx| {
103 ecx.add_goals(
105 GoalSource::AliasBoundConstCondition,
106 cx.const_conditions(alias_ty.def_id)
107 .iter_instantiated(cx, alias_ty.args)
108 .map(|trait_ref| {
109 goal.with(
110 cx,
111 trait_ref.to_host_effect_clause(cx, goal.predicate.constness),
112 )
113 }),
114 );
115 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
116 },
117 ));
118 }
119
120 candidates
121 }
122
123 fn consider_impl_candidate(
124 ecx: &mut EvalCtxt<'_, D>,
125 goal: Goal<I, Self>,
126 impl_def_id: I::DefId,
127 ) -> Result<Candidate<I>, NoSolution> {
128 let cx = ecx.cx();
129
130 let impl_trait_ref = cx.impl_trait_ref(impl_def_id);
131 if !DeepRejectCtxt::relate_rigid_infer(ecx.cx())
132 .args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
133 {
134 return Err(NoSolution);
135 }
136
137 let impl_polarity = cx.impl_polarity(impl_def_id);
138 let certainty = match impl_polarity {
139 ty::ImplPolarity::Negative => return Err(NoSolution),
140 ty::ImplPolarity::Reservation => match ecx.typing_mode() {
141 TypingMode::Coherence => Certainty::AMBIGUOUS,
142 TypingMode::Analysis { .. }
143 | TypingMode::Borrowck { .. }
144 | TypingMode::PostBorrowckAnalysis { .. }
145 | TypingMode::PostAnalysis => return Err(NoSolution),
146 },
147 ty::ImplPolarity::Positive => Certainty::Yes,
148 };
149
150 if !cx.impl_is_const(impl_def_id) {
151 return Err(NoSolution);
152 }
153
154 ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
155 let impl_args = ecx.fresh_args_for_item(impl_def_id);
156 ecx.record_impl_args(impl_args);
157 let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args);
158
159 ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
160 let where_clause_bounds = cx
161 .predicates_of(impl_def_id)
162 .iter_instantiated(cx, impl_args)
163 .map(|pred| goal.with(cx, pred));
164 ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
165
166 let const_conditions = cx
168 .const_conditions(impl_def_id)
169 .iter_instantiated(cx, impl_args)
170 .map(|bound_trait_ref| {
171 goal.with(
172 cx,
173 bound_trait_ref.to_host_effect_clause(cx, goal.predicate.constness),
174 )
175 });
176 ecx.add_goals(GoalSource::ImplWhereBound, const_conditions);
177
178 ecx.evaluate_added_goals_and_make_canonical_response(certainty)
179 })
180 }
181
182 fn consider_error_guaranteed_candidate(
183 ecx: &mut EvalCtxt<'_, D>,
184 _guar: I::ErrorGuaranteed,
185 ) -> Result<Candidate<I>, NoSolution> {
186 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
187 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
188 }
189
190 fn consider_auto_trait_candidate(
191 _ecx: &mut EvalCtxt<'_, D>,
192 _goal: Goal<I, Self>,
193 ) -> Result<Candidate<I>, NoSolution> {
194 unreachable!("auto traits are never const")
195 }
196
197 fn consider_trait_alias_candidate(
198 _ecx: &mut EvalCtxt<'_, D>,
199 _goal: Goal<I, Self>,
200 ) -> Result<Candidate<I>, NoSolution> {
201 unreachable!("trait aliases are never const")
202 }
203
204 fn consider_builtin_sizedness_candidates(
205 _ecx: &mut EvalCtxt<'_, D>,
206 _goal: Goal<I, Self>,
207 _sizedness: SizedTraitKind,
208 ) -> Result<Candidate<I>, NoSolution> {
209 unreachable!("Sized/MetaSized is never const")
210 }
211
212 fn consider_builtin_copy_clone_candidate(
213 _ecx: &mut EvalCtxt<'_, D>,
214 _goal: Goal<I, Self>,
215 ) -> Result<Candidate<I>, NoSolution> {
216 Err(NoSolution)
217 }
218
219 fn consider_builtin_fn_ptr_trait_candidate(
220 _ecx: &mut EvalCtxt<'_, D>,
221 _goal: Goal<I, Self>,
222 ) -> Result<Candidate<I>, NoSolution> {
223 todo!("Fn* are not yet const")
224 }
225
226 fn consider_builtin_fn_trait_candidates(
227 ecx: &mut EvalCtxt<'_, D>,
228 goal: Goal<I, Self>,
229 _kind: rustc_type_ir::ClosureKind,
230 ) -> Result<Candidate<I>, NoSolution> {
231 let cx = ecx.cx();
232
233 let self_ty = goal.predicate.self_ty();
234 let (inputs_and_output, def_id, args) =
235 structural_traits::extract_fn_def_from_const_callable(cx, self_ty)?;
236
237 let output_is_sized_pred = inputs_and_output.map_bound(|(_, output)| {
240 ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output])
241 });
242 let requirements = cx
243 .const_conditions(def_id)
244 .iter_instantiated(cx, args)
245 .map(|trait_ref| {
246 (
247 GoalSource::ImplWhereBound,
248 goal.with(cx, trait_ref.to_host_effect_clause(cx, goal.predicate.constness)),
249 )
250 })
251 .chain([(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))]);
252
253 let pred = inputs_and_output
254 .map_bound(|(inputs, _)| {
255 ty::TraitRef::new(
256 cx,
257 goal.predicate.def_id(),
258 [goal.predicate.self_ty(), Ty::new_tup(cx, inputs.as_slice())],
259 )
260 })
261 .to_host_effect_clause(cx, goal.predicate.constness);
262
263 Self::probe_and_consider_implied_clause(
264 ecx,
265 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
266 goal,
267 pred,
268 requirements,
269 )
270 }
271
272 fn consider_builtin_async_fn_trait_candidates(
273 _ecx: &mut EvalCtxt<'_, D>,
274 _goal: Goal<I, Self>,
275 _kind: rustc_type_ir::ClosureKind,
276 ) -> Result<Candidate<I>, NoSolution> {
277 todo!("AsyncFn* are not yet const")
278 }
279
280 fn consider_builtin_async_fn_kind_helper_candidate(
281 _ecx: &mut EvalCtxt<'_, D>,
282 _goal: Goal<I, Self>,
283 ) -> Result<Candidate<I>, NoSolution> {
284 unreachable!("AsyncFnKindHelper is not const")
285 }
286
287 fn consider_builtin_tuple_candidate(
288 _ecx: &mut EvalCtxt<'_, D>,
289 _goal: Goal<I, Self>,
290 ) -> Result<Candidate<I>, NoSolution> {
291 unreachable!("Tuple trait is not const")
292 }
293
294 fn consider_builtin_pointee_candidate(
295 _ecx: &mut EvalCtxt<'_, D>,
296 _goal: Goal<I, Self>,
297 ) -> Result<Candidate<I>, NoSolution> {
298 unreachable!("Pointee is not const")
299 }
300
301 fn consider_builtin_future_candidate(
302 _ecx: &mut EvalCtxt<'_, D>,
303 _goal: Goal<I, Self>,
304 ) -> Result<Candidate<I>, NoSolution> {
305 unreachable!("Future is not const")
306 }
307
308 fn consider_builtin_iterator_candidate(
309 _ecx: &mut EvalCtxt<'_, D>,
310 _goal: Goal<I, Self>,
311 ) -> Result<Candidate<I>, NoSolution> {
312 todo!("Iterator is not yet const")
313 }
314
315 fn consider_builtin_fused_iterator_candidate(
316 _ecx: &mut EvalCtxt<'_, D>,
317 _goal: Goal<I, Self>,
318 ) -> Result<Candidate<I>, NoSolution> {
319 unreachable!("FusedIterator is not const")
320 }
321
322 fn consider_builtin_async_iterator_candidate(
323 _ecx: &mut EvalCtxt<'_, D>,
324 _goal: Goal<I, Self>,
325 ) -> Result<Candidate<I>, NoSolution> {
326 unreachable!("AsyncIterator is not const")
327 }
328
329 fn consider_builtin_coroutine_candidate(
330 _ecx: &mut EvalCtxt<'_, D>,
331 _goal: Goal<I, Self>,
332 ) -> Result<Candidate<I>, NoSolution> {
333 unreachable!("Coroutine is not const")
334 }
335
336 fn consider_builtin_discriminant_kind_candidate(
337 _ecx: &mut EvalCtxt<'_, D>,
338 _goal: Goal<I, Self>,
339 ) -> Result<Candidate<I>, NoSolution> {
340 unreachable!("DiscriminantKind is not const")
341 }
342
343 fn consider_builtin_destruct_candidate(
344 ecx: &mut EvalCtxt<'_, D>,
345 goal: Goal<I, Self>,
346 ) -> Result<Candidate<I>, NoSolution> {
347 let cx = ecx.cx();
348
349 let self_ty = goal.predicate.self_ty();
350 let const_conditions = structural_traits::const_conditions_for_destruct(cx, self_ty)?;
351
352 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
353 ecx.add_goals(
354 GoalSource::AliasBoundConstCondition,
355 const_conditions.into_iter().map(|trait_ref| {
356 goal.with(
357 cx,
358 ty::Binder::dummy(trait_ref)
359 .to_host_effect_clause(cx, goal.predicate.constness),
360 )
361 }),
362 );
363 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
364 })
365 }
366
367 fn consider_builtin_transmute_candidate(
368 _ecx: &mut EvalCtxt<'_, D>,
369 _goal: Goal<I, Self>,
370 ) -> Result<Candidate<I>, NoSolution> {
371 unreachable!("TransmuteFrom is not const")
372 }
373
374 fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
375 _ecx: &mut EvalCtxt<'_, D>,
376 _goal: Goal<I, Self>,
377 ) -> Result<Candidate<I>, NoSolution> {
378 unreachable!("BikeshedGuaranteedNoDrop is not const");
379 }
380
381 fn consider_structural_builtin_unsize_candidates(
382 _ecx: &mut EvalCtxt<'_, D>,
383 _goal: Goal<I, Self>,
384 ) -> Vec<Candidate<I>> {
385 unreachable!("Unsize is not const")
386 }
387}
388
389impl<D, I> EvalCtxt<'_, D>
390where
391 D: SolverDelegate<Interner = I>,
392 I: Interner,
393{
394 #[instrument(level = "trace", skip(self))]
395 pub(super) fn compute_host_effect_goal(
396 &mut self,
397 goal: Goal<I, ty::HostEffectPredicate<I>>,
398 ) -> QueryResult<I> {
399 let (_, proven_via) = self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
400 let trait_goal: Goal<I, ty::TraitPredicate<I>> =
401 goal.with(ecx.cx(), goal.predicate.trait_ref);
402 ecx.compute_trait_goal(trait_goal)
403 })?;
404 self.assemble_and_merge_candidates(proven_via, goal, |_ecx| Err(NoSolution))
405 }
406}