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 ) -> Result<(), NoSolution> {
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 Ok(())
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 match impl_polarity {
139 ty::ImplPolarity::Negative => return Err(NoSolution),
140 ty::ImplPolarity::Reservation => {
141 unimplemented!("reservation impl for const trait: {:?}", goal)
142 }
143 ty::ImplPolarity::Positive => {}
144 };
145
146 if !cx.impl_is_const(impl_def_id) {
147 return Err(NoSolution);
148 }
149
150 ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
151 let impl_args = ecx.fresh_args_for_item(impl_def_id);
152 ecx.record_impl_args(impl_args);
153 let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args);
154
155 ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
156 let where_clause_bounds = cx
157 .predicates_of(impl_def_id)
158 .iter_instantiated(cx, impl_args)
159 .map(|pred| goal.with(cx, pred));
160 ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
161
162 let const_conditions = cx
164 .const_conditions(impl_def_id)
165 .iter_instantiated(cx, impl_args)
166 .map(|bound_trait_ref| {
167 goal.with(
168 cx,
169 bound_trait_ref.to_host_effect_clause(cx, goal.predicate.constness),
170 )
171 });
172 ecx.add_goals(GoalSource::ImplWhereBound, const_conditions);
173
174 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
175 })
176 }
177
178 fn consider_error_guaranteed_candidate(
179 ecx: &mut EvalCtxt<'_, D>,
180 _guar: I::ErrorGuaranteed,
181 ) -> Result<Candidate<I>, NoSolution> {
182 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
183 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
184 }
185
186 fn consider_auto_trait_candidate(
187 _ecx: &mut EvalCtxt<'_, D>,
188 _goal: Goal<I, Self>,
189 ) -> Result<Candidate<I>, NoSolution> {
190 unreachable!("auto traits are never const")
191 }
192
193 fn consider_trait_alias_candidate(
194 _ecx: &mut EvalCtxt<'_, D>,
195 _goal: Goal<I, Self>,
196 ) -> Result<Candidate<I>, NoSolution> {
197 unreachable!("trait aliases are never const")
198 }
199
200 fn consider_builtin_sized_candidate(
201 _ecx: &mut EvalCtxt<'_, D>,
202 _goal: Goal<I, Self>,
203 ) -> Result<Candidate<I>, NoSolution> {
204 unreachable!("Sized is never const")
205 }
206
207 fn consider_builtin_copy_clone_candidate(
208 _ecx: &mut EvalCtxt<'_, D>,
209 _goal: Goal<I, Self>,
210 ) -> Result<Candidate<I>, NoSolution> {
211 Err(NoSolution)
212 }
213
214 fn consider_builtin_fn_ptr_trait_candidate(
215 _ecx: &mut EvalCtxt<'_, D>,
216 _goal: Goal<I, Self>,
217 ) -> Result<Candidate<I>, NoSolution> {
218 todo!("Fn* are not yet const")
219 }
220
221 fn consider_builtin_fn_trait_candidates(
222 ecx: &mut EvalCtxt<'_, D>,
223 goal: Goal<I, Self>,
224 _kind: rustc_type_ir::ClosureKind,
225 ) -> Result<Candidate<I>, NoSolution> {
226 let cx = ecx.cx();
227
228 let self_ty = goal.predicate.self_ty();
229 let (inputs_and_output, def_id, args) =
230 structural_traits::extract_fn_def_from_const_callable(cx, self_ty)?;
231
232 let output_is_sized_pred = inputs_and_output.map_bound(|(_, output)| {
235 ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output])
236 });
237 let requirements = cx
238 .const_conditions(def_id)
239 .iter_instantiated(cx, args)
240 .map(|trait_ref| {
241 (
242 GoalSource::ImplWhereBound,
243 goal.with(cx, trait_ref.to_host_effect_clause(cx, goal.predicate.constness)),
244 )
245 })
246 .chain([(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))]);
247
248 let pred = inputs_and_output
249 .map_bound(|(inputs, _)| {
250 ty::TraitRef::new(
251 cx,
252 goal.predicate.def_id(),
253 [goal.predicate.self_ty(), Ty::new_tup(cx, inputs.as_slice())],
254 )
255 })
256 .to_host_effect_clause(cx, goal.predicate.constness);
257
258 Self::probe_and_consider_implied_clause(
259 ecx,
260 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
261 goal,
262 pred,
263 requirements,
264 )
265 }
266
267 fn consider_builtin_async_fn_trait_candidates(
268 _ecx: &mut EvalCtxt<'_, D>,
269 _goal: Goal<I, Self>,
270 _kind: rustc_type_ir::ClosureKind,
271 ) -> Result<Candidate<I>, NoSolution> {
272 todo!("AsyncFn* are not yet const")
273 }
274
275 fn consider_builtin_async_fn_kind_helper_candidate(
276 _ecx: &mut EvalCtxt<'_, D>,
277 _goal: Goal<I, Self>,
278 ) -> Result<Candidate<I>, NoSolution> {
279 unreachable!("AsyncFnKindHelper is not const")
280 }
281
282 fn consider_builtin_tuple_candidate(
283 _ecx: &mut EvalCtxt<'_, D>,
284 _goal: Goal<I, Self>,
285 ) -> Result<Candidate<I>, NoSolution> {
286 unreachable!("Tuple trait is not const")
287 }
288
289 fn consider_builtin_pointee_candidate(
290 _ecx: &mut EvalCtxt<'_, D>,
291 _goal: Goal<I, Self>,
292 ) -> Result<Candidate<I>, NoSolution> {
293 unreachable!("Pointee is not const")
294 }
295
296 fn consider_builtin_future_candidate(
297 _ecx: &mut EvalCtxt<'_, D>,
298 _goal: Goal<I, Self>,
299 ) -> Result<Candidate<I>, NoSolution> {
300 unreachable!("Future is not const")
301 }
302
303 fn consider_builtin_iterator_candidate(
304 _ecx: &mut EvalCtxt<'_, D>,
305 _goal: Goal<I, Self>,
306 ) -> Result<Candidate<I>, NoSolution> {
307 todo!("Iterator is not yet const")
308 }
309
310 fn consider_builtin_fused_iterator_candidate(
311 _ecx: &mut EvalCtxt<'_, D>,
312 _goal: Goal<I, Self>,
313 ) -> Result<Candidate<I>, NoSolution> {
314 unreachable!("FusedIterator is not const")
315 }
316
317 fn consider_builtin_async_iterator_candidate(
318 _ecx: &mut EvalCtxt<'_, D>,
319 _goal: Goal<I, Self>,
320 ) -> Result<Candidate<I>, NoSolution> {
321 unreachable!("AsyncIterator is not const")
322 }
323
324 fn consider_builtin_coroutine_candidate(
325 _ecx: &mut EvalCtxt<'_, D>,
326 _goal: Goal<I, Self>,
327 ) -> Result<Candidate<I>, NoSolution> {
328 unreachable!("Coroutine is not const")
329 }
330
331 fn consider_builtin_discriminant_kind_candidate(
332 _ecx: &mut EvalCtxt<'_, D>,
333 _goal: Goal<I, Self>,
334 ) -> Result<Candidate<I>, NoSolution> {
335 unreachable!("DiscriminantKind is not const")
336 }
337
338 fn consider_builtin_destruct_candidate(
339 ecx: &mut EvalCtxt<'_, D>,
340 goal: Goal<I, Self>,
341 ) -> Result<Candidate<I>, NoSolution> {
342 let cx = ecx.cx();
343
344 let self_ty = goal.predicate.self_ty();
345 let const_conditions = structural_traits::const_conditions_for_destruct(cx, self_ty)?;
346
347 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
348 ecx.add_goals(
349 GoalSource::AliasBoundConstCondition,
350 const_conditions.into_iter().map(|trait_ref| {
351 goal.with(
352 cx,
353 ty::Binder::dummy(trait_ref)
354 .to_host_effect_clause(cx, goal.predicate.constness),
355 )
356 }),
357 );
358 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
359 })
360 }
361
362 fn consider_builtin_transmute_candidate(
363 _ecx: &mut EvalCtxt<'_, D>,
364 _goal: Goal<I, Self>,
365 ) -> Result<Candidate<I>, NoSolution> {
366 unreachable!("TransmuteFrom is not const")
367 }
368
369 fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
370 _ecx: &mut EvalCtxt<'_, D>,
371 _goal: Goal<I, Self>,
372 ) -> Result<Candidate<I>, NoSolution> {
373 unreachable!("BikeshedGuaranteedNoDrop is not const");
374 }
375
376 fn consider_structural_builtin_unsize_candidates(
377 _ecx: &mut EvalCtxt<'_, D>,
378 _goal: Goal<I, Self>,
379 ) -> Vec<Candidate<I>> {
380 unreachable!("Unsize is not const")
381 }
382}
383
384impl<D, I> EvalCtxt<'_, D>
385where
386 D: SolverDelegate<Interner = I>,
387 I: Interner,
388{
389 #[instrument(level = "trace", skip(self))]
390 pub(super) fn compute_host_effect_goal(
391 &mut self,
392 goal: Goal<I, ty::HostEffectPredicate<I>>,
393 ) -> QueryResult<I> {
394 let (_, proven_via) = self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
395 let trait_goal: Goal<I, ty::TraitPredicate<I>> =
396 goal.with(ecx.cx(), goal.predicate.trait_ref);
397 ecx.compute_trait_goal(trait_goal)
398 })?;
399 self.assemble_and_merge_candidates(proven_via, goal, |_ecx| Err(NoSolution))
400 }
401}