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