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