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::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 fast_reject_assumption(
40 ecx: &mut EvalCtxt<'_, D>,
41 goal: Goal<I, Self>,
42 assumption: I::Clause,
43 ) -> Result<(), NoSolution> {
44 if let Some(host_clause) = assumption.as_host_effect_clause() {
45 if host_clause.def_id() == goal.predicate.def_id()
46 && host_clause.constness().satisfies(goal.predicate.constness)
47 {
48 if 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 return Ok(());
53 }
54 }
55 }
56
57 Err(NoSolution)
58 }
59
60 fn match_assumption(
61 ecx: &mut EvalCtxt<'_, D>,
62 goal: Goal<I, Self>,
63 assumption: I::Clause,
64 then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
65 ) -> QueryResult<I> {
66 let host_clause = assumption.as_host_effect_clause().unwrap();
67
68 let assumption_trait_pred = ecx.instantiate_binder_with_infer(host_clause);
69 ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
70
71 then(ecx)
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::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::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_destruct_candidate(
340 ecx: &mut EvalCtxt<'_, D>,
341 goal: Goal<I, Self>,
342 ) -> Result<Candidate<I>, NoSolution> {
343 let cx = ecx.cx();
344
345 let self_ty = goal.predicate.self_ty();
346 let const_conditions = structural_traits::const_conditions_for_destruct(cx, self_ty)?;
347
348 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
349 ecx.add_goals(
350 GoalSource::AliasBoundConstCondition,
351 const_conditions.into_iter().map(|trait_ref| {
352 goal.with(
353 cx,
354 ty::Binder::dummy(trait_ref)
355 .to_host_effect_clause(cx, goal.predicate.constness),
356 )
357 }),
358 );
359 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
360 })
361 }
362
363 fn consider_builtin_transmute_candidate(
364 _ecx: &mut EvalCtxt<'_, D>,
365 _goal: Goal<I, Self>,
366 ) -> Result<Candidate<I>, NoSolution> {
367 unreachable!("TransmuteFrom is not const")
368 }
369
370 fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
371 _ecx: &mut EvalCtxt<'_, D>,
372 _goal: Goal<I, Self>,
373 ) -> Result<Candidate<I>, NoSolution> {
374 unreachable!("BikeshedGuaranteedNoDrop is not const");
375 }
376
377 fn consider_structural_builtin_unsize_candidates(
378 _ecx: &mut EvalCtxt<'_, D>,
379 _goal: Goal<I, Self>,
380 ) -> Vec<Candidate<I>> {
381 unreachable!("Unsize is not const")
382 }
383}
384
385impl<D, I> EvalCtxt<'_, D>
386where
387 D: SolverDelegate<Interner = I>,
388 I: Interner,
389{
390 #[instrument(level = "trace", skip(self))]
391 pub(super) fn compute_host_effect_goal(
392 &mut self,
393 goal: Goal<I, ty::HostEffectPredicate<I>>,
394 ) -> QueryResult<I> {
395 let (_, proven_via) = self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
396 let trait_goal: Goal<I, ty::TraitPredicate<I>> =
397 goal.with(ecx.cx(), goal.predicate.trait_ref);
398 ecx.compute_trait_goal(trait_goal)
399 })?;
400 self.assemble_and_merge_candidates(proven_via, goal, |_ecx| Err(NoSolution))
401 }
402}