1use rustc_type_ir::fast_reject::DeepRejectCtxt;
5use rustc_type_ir::inherent::*;
6use rustc_type_ir::lang_items::SolverTraitLangItem;
7use rustc_type_ir::solve::inspect::ProbeKind;
8use rustc_type_ir::solve::{
9 AliasBoundKind, NoSolutionOrRerunNonErased, QueryResultOrRerunNonErased, RerunNonErased,
10 SizedTraitKind,
11};
12use rustc_type_ir::{self as ty, Interner, Unnormalized, elaborate};
13use tracing::instrument;
14
15use super::assembly::{Candidate, structural_traits};
16use crate::delegate::SolverDelegate;
17use crate::solve::{
18 BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution, assembly,
19};
20
21impl<D, I> assembly::GoalKind<D> for ty::HostEffectClause<I>
22where
23 D: SolverDelegate<Interner = I>,
24 I: Interner,
25{
26 fn self_ty(self) -> I::Ty {
27 self.self_ty()
28 }
29
30 fn trait_ref(self, _: I) -> ty::TraitRef<I> {
31 self.trait_ref
32 }
33
34 fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self {
35 self.with_replaced_self_ty(cx, self_ty)
36 }
37
38 fn trait_def_id(self, _: I) -> I::TraitId {
39 self.def_id()
40 }
41
42 fn fast_reject_assumption(
43 ecx: &mut EvalCtxt<'_, D>,
44 goal: Goal<I, Self>,
45 assumption: I::Clause,
46 ) -> Result<(), NoSolution> {
47 if let Some(host_clause) = assumption.as_host_effect_clause()
48 && host_clause.def_id() == goal.predicate.def_id()
49 && host_clause.constness().satisfies(goal.predicate.constness)
50 && 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 {
55 Ok(())
56 } else {
57 Err(NoSolution)
58 }
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>) -> QueryResultOrRerunNonErased<I>,
66 ) -> QueryResultOrRerunNonErased<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 = ::alloc::vec::Vec::new()vec![];
88
89 let def_id = match alias_ty.kind {
90 ty::AliasTyKind::Projection { def_id } => def_id.into(),
91 ty::AliasTyKind::Inherent { def_id } => def_id.into(),
92 ty::AliasTyKind::Opaque { def_id } => def_id.into(),
93 ty::AliasTyKind::Free { def_id } => def_id.into(),
94 };
95
96 if !ecx.cx().alias_has_const_conditions(def_id) {
97 return ::alloc::vec::Vec::new()vec![];
98 }
99
100 for clause in elaborate::elaborate(
101 cx,
102 cx.explicit_implied_const_bounds(def_id).iter_instantiated(cx, alias_ty.args).map(
103 |trait_ref| {
104 trait_ref.to_host_effect_clause(cx, goal.predicate.constness).skip_norm_wip()
105 },
106 ),
107 ) {
108 candidates.extend(Self::probe_and_match_goal_against_assumption(
109 ecx,
110 CandidateSource::AliasBound(AliasBoundKind::SelfBounds),
111 goal,
112 clause,
113 |ecx| {
114 ecx.add_goals(
116 GoalSource::AliasBoundConstCondition,
117 cx.const_conditions(def_id).iter_instantiated(cx, alias_ty.args).map(
118 |trait_ref| {
119 goal.with(
120 cx,
121 trait_ref
122 .to_host_effect_clause(cx, goal.predicate.constness)
123 .skip_norm_wip(),
124 )
125 },
126 ),
127 )?;
128 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
129 },
130 ));
131 }
132
133 candidates
134 }
135
136 fn consider_impl_candidate(
137 ecx: &mut EvalCtxt<'_, D>,
138 goal: Goal<I, Self>,
139 goal_trait_ref: ty::TraitRef<I>,
140 impl_def_id: I::ImplId,
141 then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResultOrRerunNonErased<I>,
142 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
143 let cx = ecx.cx();
144
145 let impl_trait_ref = cx.impl_trait_ref(impl_def_id);
146 if !DeepRejectCtxt::relate_rigid_infer(ecx.cx())
147 .args_may_unify(goal_trait_ref.args, impl_trait_ref.skip_binder().args)
148 {
149 return Err(NoSolution.into());
150 }
151
152 if cx.impl_is_default(impl_def_id) {
156 return Err(NoSolution.into());
157 }
158
159 let impl_polarity = cx.impl_polarity(impl_def_id);
160 let certainty = match impl_polarity {
161 ty::ImplPolarity::Negative => return Err(NoSolution.into()),
162 ty::ImplPolarity::Reservation => {
163 if ecx.typing_mode().is_coherence() {
164 Certainty::AMBIGUOUS
165 } else {
166 return Err(NoSolution.into());
167 }
168 }
169 ty::ImplPolarity::Positive => Certainty::Yes,
170 };
171
172 if !cx.impl_is_const(impl_def_id) {
173 return Err(NoSolution.into());
174 }
175
176 ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
177 let impl_args = ecx.fresh_args_for_item(impl_def_id.into());
178 ecx.record_impl_args(impl_args);
179 let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args).skip_norm_wip();
180
181 ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?;
182 let where_clause_bounds = cx
183 .clauses_of(impl_def_id.into())
184 .iter_instantiated(cx, impl_args)
185 .map(Unnormalized::skip_norm_wip)
186 .map(|clause| goal.with(cx, clause));
187 ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds)?;
188
189 let const_conditions = cx
191 .const_conditions(impl_def_id.into())
192 .iter_instantiated(cx, impl_args)
193 .map(|bound_trait_ref| {
194 goal.with(
195 cx,
196 bound_trait_ref
197 .to_host_effect_clause(cx, goal.predicate.constness)
198 .skip_norm_wip(),
199 )
200 });
201 ecx.add_goals(GoalSource::ImplWhereBound, const_conditions)?;
202
203 then(ecx, certainty)
204 })
205 }
206
207 fn consider_error_guaranteed_candidate(
208 ecx: &mut EvalCtxt<'_, D>,
209 _goal: Goal<I, Self>,
210 _guar: I::ErrorGuaranteed,
211 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
212 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
213 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
214 }
215
216 fn consider_auto_trait_candidate(
217 ecx: &mut EvalCtxt<'_, D>,
218 _goal: Goal<I, Self>,
219 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
220 ecx.cx().delay_bug("auto traits are never const");
221 Err(NoSolution.into())
222 }
223
224 fn consider_trait_alias_candidate(
225 ecx: &mut EvalCtxt<'_, D>,
226 goal: Goal<I, Self>,
227 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
228 let cx = ecx.cx();
229
230 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
231 let where_clause_bounds = cx
232 .clauses_of(goal.predicate.def_id().into())
233 .iter_instantiated(cx, goal.predicate.trait_ref.args)
234 .map(Unnormalized::skip_norm_wip)
235 .map(|c| goal.with(cx, c));
236
237 let const_conditions = cx
238 .const_conditions(goal.predicate.def_id().into())
239 .iter_instantiated(cx, goal.predicate.trait_ref.args)
240 .map(|bound_trait_ref| {
241 goal.with(
242 cx,
243 bound_trait_ref
244 .to_host_effect_clause(cx, goal.predicate.constness)
245 .skip_norm_wip(),
246 )
247 });
248 ecx.add_goals(GoalSource::Misc, where_clause_bounds)?;
254 ecx.add_goals(GoalSource::Misc, const_conditions)?;
255 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
256 })
257 }
258
259 fn consider_builtin_sizedness_candidates(
260 _ecx: &mut EvalCtxt<'_, D>,
261 _goal: Goal<I, Self>,
262 _sizedness: SizedTraitKind,
263 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
264 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("Sized/MetaSized is never const")));
}unreachable!("Sized/MetaSized is never const")
265 }
266
267 fn consider_builtin_copy_clone_candidate(
268 ecx: &mut EvalCtxt<'_, D>,
269 goal: Goal<I, Self>,
270 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
271 let cx = ecx.cx();
272
273 let self_ty = goal.predicate.self_ty();
274 let constituent_tys =
275 structural_traits::instantiate_constituent_tys_for_copy_clone_trait(ecx, self_ty)?;
276
277 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
278 ecx.enter_forall_with_assumptions(constituent_tys, goal.param_env, |ecx, tys| {
279 ecx.add_goals(
280 GoalSource::ImplWhereBound,
281 tys.into_iter().map(|ty| {
282 goal.with(
283 cx,
284 ty::ClauseKind::HostEffect(
285 goal.predicate.with_replaced_self_ty(cx, ty),
286 ),
287 )
288 }),
289 )
290 })?;
291
292 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
293 })
294 }
295
296 fn consider_builtin_fn_ptr_trait_candidate(
297 _ecx: &mut EvalCtxt<'_, D>,
298 _goal: Goal<I, Self>,
299 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
300 {
::core::panicking::panic_fmt(format_args!("not implemented: {0}",
format_args!("Fn* are not yet const")));
}unimplemented!("Fn* are not yet const")
301 }
302
303 x;#[instrument(level = "trace", skip_all, ret)]
304 fn consider_builtin_fn_trait_candidates(
305 ecx: &mut EvalCtxt<'_, D>,
306 goal: Goal<I, Self>,
307 _kind: rustc_type_ir::ClosureKind,
308 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
309 let cx = ecx.cx();
310
311 let self_ty = goal.predicate.self_ty();
312 let (inputs_and_output, def_id, args) =
313 structural_traits::extract_fn_def_from_const_callable(cx, self_ty)?;
314 let (inputs, output) = ecx.instantiate_binder_with_infer(inputs_and_output);
315
316 let output_is_sized_pred =
319 ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]);
320 let requirements = cx
321 .const_conditions(def_id)
322 .iter_instantiated(cx, args)
323 .map(|trait_ref| {
324 (
325 GoalSource::ImplWhereBound,
326 goal.with(
327 cx,
328 trait_ref
329 .to_host_effect_clause(cx, goal.predicate.constness)
330 .skip_norm_wip(),
331 ),
332 )
333 })
334 .chain([(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))]);
335
336 let pred = ty::Binder::dummy(ty::TraitRef::new(
337 cx,
338 goal.predicate.def_id(),
339 [goal.predicate.self_ty(), inputs],
340 ))
341 .to_host_effect_clause(cx, goal.predicate.constness);
342
343 Self::probe_and_consider_implied_clause(
344 ecx,
345 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
346 goal,
347 pred,
348 requirements,
349 )
350 .map_err(Into::into)
351 }
352
353 fn consider_builtin_async_fn_trait_candidates(
354 _ecx: &mut EvalCtxt<'_, D>,
355 _goal: Goal<I, Self>,
356 _kind: rustc_type_ir::ClosureKind,
357 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
358 {
::core::panicking::panic_fmt(format_args!("not implemented: {0}",
format_args!("AsyncFn* are not yet const")));
}unimplemented!("AsyncFn* are not yet const")
359 }
360
361 fn consider_builtin_async_fn_kind_helper_candidate(
362 _ecx: &mut EvalCtxt<'_, D>,
363 _goal: Goal<I, Self>,
364 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
365 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("AsyncFnKindHelper is not const")));
}unreachable!("AsyncFnKindHelper is not const")
366 }
367
368 fn consider_builtin_tuple_candidate(
369 _ecx: &mut EvalCtxt<'_, D>,
370 _goal: Goal<I, Self>,
371 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
372 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("Tuple trait is not const")));
}unreachable!("Tuple trait is not const")
373 }
374
375 fn consider_builtin_pointee_candidate(
376 _ecx: &mut EvalCtxt<'_, D>,
377 _goal: Goal<I, Self>,
378 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
379 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("Pointee is not const")));
}unreachable!("Pointee is not const")
380 }
381
382 fn consider_builtin_future_candidate(
383 _ecx: &mut EvalCtxt<'_, D>,
384 _goal: Goal<I, Self>,
385 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
386 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("Future is not const")));
}unreachable!("Future is not const")
387 }
388
389 fn consider_builtin_iterator_candidate(
390 _ecx: &mut EvalCtxt<'_, D>,
391 _goal: Goal<I, Self>,
392 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
393 Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution))
394 }
395
396 fn consider_builtin_fused_iterator_candidate(
397 _ecx: &mut EvalCtxt<'_, D>,
398 _goal: Goal<I, Self>,
399 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
400 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("FusedIterator is not const")));
}unreachable!("FusedIterator is not const")
401 }
402
403 fn consider_builtin_async_iterator_candidate(
404 _ecx: &mut EvalCtxt<'_, D>,
405 _goal: Goal<I, Self>,
406 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
407 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("AsyncIterator is not const")));
}unreachable!("AsyncIterator is not const")
408 }
409
410 fn consider_builtin_coroutine_candidate(
411 _ecx: &mut EvalCtxt<'_, D>,
412 _goal: Goal<I, Self>,
413 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
414 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("Coroutine is not const")));
}unreachable!("Coroutine is not const")
415 }
416
417 fn consider_builtin_discriminant_kind_candidate(
418 _ecx: &mut EvalCtxt<'_, D>,
419 _goal: Goal<I, Self>,
420 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
421 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("DiscriminantKind is not const")));
}unreachable!("DiscriminantKind is not const")
422 }
423
424 fn consider_builtin_destruct_candidate(
425 ecx: &mut EvalCtxt<'_, D>,
426 goal: Goal<I, Self>,
427 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
428 let cx = ecx.cx();
429
430 let self_ty = goal.predicate.self_ty();
431 let const_conditions = structural_traits::const_conditions_for_destruct(cx, self_ty)?;
432
433 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
434 ecx.add_goals(
435 GoalSource::AliasBoundConstCondition,
436 const_conditions.into_iter().map(|trait_ref| {
437 goal.with(
438 cx,
439 ty::Binder::dummy(trait_ref)
440 .to_host_effect_clause(cx, goal.predicate.constness),
441 )
442 }),
443 )?;
444 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
445 })
446 }
447
448 fn consider_builtin_transmute_candidate(
449 _ecx: &mut EvalCtxt<'_, D>,
450 _goal: Goal<I, Self>,
451 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
452 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("TransmuteFrom is not const")));
}unreachable!("TransmuteFrom is not const")
453 }
454
455 fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
456 _ecx: &mut EvalCtxt<'_, D>,
457 _goal: Goal<I, Self>,
458 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
459 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("BikeshedGuaranteedNoDrop is not const")));
};unreachable!("BikeshedGuaranteedNoDrop is not const");
460 }
461
462 fn consider_builtin_try_as_dyn_candidate(
463 _ecx: &mut EvalCtxt<'_, D>,
464 goal: Goal<I, Self>,
465 ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
466 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("`TryAsDynCompat` is not const: {0:?}", goal)));
}unreachable!("`TryAsDynCompat` is not const: {:?}", goal)
467 }
468
469 fn consider_structural_builtin_unsize_candidates(
470 _ecx: &mut EvalCtxt<'_, D>,
471 _goal: Goal<I, Self>,
472 ) -> Result<Vec<Candidate<I>>, RerunNonErased> {
473 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("Unsize is not const")));
}unreachable!("Unsize is not const")
474 }
475
476 fn consider_builtin_field_candidate(
477 _ecx: &mut EvalCtxt<'_, D>,
478 _goal: Goal<<D as SolverDelegate>::Interner, Self>,
479 ) -> Result<Candidate<<D as SolverDelegate>::Interner>, NoSolutionOrRerunNonErased> {
480 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("Field is not const")));
}unreachable!("Field is not const")
481 }
482}
483
484impl<D, I> EvalCtxt<'_, D>
485where
486 D: SolverDelegate<Interner = I>,
487 I: Interner,
488{
489 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("compute_host_effect_goal",
"rustc_next_trait_solver::solve::effect_goals",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_next_trait_solver/src/solve/effect_goals.rs"),
::tracing_core::__macro_support::Option::Some(489u32),
::tracing_core::__macro_support::Option::Some("rustc_next_trait_solver::solve::effect_goals"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("goal")
}> =
::tracing::__macro_support::FieldName::new("goal");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&goal)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: QueryResultOrRerunNonErased<I> =
loop {};
return __tracing_attr_fake_return;
}
{
let (_, proven_via) =
self.probe(|_|
ProbeKind::ShadowedEnvProbing).enter(|ecx|
{
let trait_goal: Goal<I, ty::TraitClause<I>> =
goal.with(ecx.cx(), goal.predicate.trait_ref);
ecx.compute_trait_goal(trait_goal).map_err(Into::into)
})?;
self.assemble_and_merge_candidates(proven_via, goal, |_ecx| None,
|_ecx| Err(NoSolution.into()))
}
}
}#[instrument(level = "trace", skip(self))]
490 pub(super) fn compute_host_effect_goal(
491 &mut self,
492 goal: Goal<I, ty::HostEffectClause<I>>,
493 ) -> QueryResultOrRerunNonErased<I> {
494 let (_, proven_via) = self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
495 let trait_goal: Goal<I, ty::TraitClause<I>> =
496 goal.with(ecx.cx(), goal.predicate.trait_ref);
497 ecx.compute_trait_goal(trait_goal).map_err(Into::into)
498 })?;
499 self.assemble_and_merge_candidates(
500 proven_via,
501 goal,
502 |_ecx| None,
503 |_ecx| Err(NoSolution.into()),
504 )
505 }
506}