1use rustc_type_ir::data_structures::IndexSet;
4use rustc_type_ir::fast_reject::DeepRejectCtxt;
5use rustc_type_ir::inherent::*;
6use rustc_type_ir::lang_items::SolverTraitLangItem;
7use rustc_type_ir::solve::{CanonicalResponse, SizedTraitKind};
8use rustc_type_ir::{
9 self as ty, Interner, Movability, PredicatePolarity, TraitPredicate, TraitRef,
10 TypeVisitableExt as _, TypingMode, Upcast as _, elaborate,
11};
12use tracing::{debug, instrument, trace};
13
14use crate::delegate::SolverDelegate;
15use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
16use crate::solve::assembly::{
17 self, AllowInferenceConstraints, AssembleCandidatesFrom, Candidate, FailedCandidateInfo,
18};
19use crate::solve::inspect::ProbeKind;
20use crate::solve::{
21 BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
22 MergeCandidateInfo, NoSolution, ParamEnvSource, QueryResult, has_only_region_constraints,
23};
24
25impl<D, I> assembly::GoalKind<D> for TraitPredicate<I>
26where
27 D: SolverDelegate<Interner = I>,
28 I: Interner,
29{
30 fn self_ty(self) -> I::Ty {
31 self.self_ty()
32 }
33
34 fn trait_ref(self, _: I) -> ty::TraitRef<I> {
35 self.trait_ref
36 }
37
38 fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self {
39 self.with_replaced_self_ty(cx, self_ty)
40 }
41
42 fn trait_def_id(self, _: I) -> I::TraitId {
43 self.def_id()
44 }
45
46 fn consider_additional_alias_assumptions(
47 _ecx: &mut EvalCtxt<'_, D>,
48 _goal: Goal<I, Self>,
49 _alias_ty: ty::AliasTy<I>,
50 ) -> Vec<Candidate<I>> {
51 vec![]
52 }
53
54 fn consider_impl_candidate(
55 ecx: &mut EvalCtxt<'_, D>,
56 goal: Goal<I, TraitPredicate<I>>,
57 impl_def_id: I::ImplId,
58 then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>,
59 ) -> Result<Candidate<I>, NoSolution> {
60 let cx = ecx.cx();
61
62 let impl_trait_ref = cx.impl_trait_ref(impl_def_id);
63 if !DeepRejectCtxt::relate_rigid_infer(ecx.cx())
64 .args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
65 {
66 return Err(NoSolution);
67 }
68
69 let impl_polarity = cx.impl_polarity(impl_def_id);
72 let maximal_certainty = match (impl_polarity, goal.predicate.polarity) {
73 (ty::ImplPolarity::Reservation, _) => match ecx.typing_mode() {
76 TypingMode::Coherence => Certainty::AMBIGUOUS,
77 TypingMode::Analysis { .. }
78 | TypingMode::Borrowck { .. }
79 | TypingMode::PostBorrowckAnalysis { .. }
80 | TypingMode::PostAnalysis => return Err(NoSolution),
81 },
82
83 (ty::ImplPolarity::Positive, ty::PredicatePolarity::Positive)
85 | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => Certainty::Yes,
86
87 (ty::ImplPolarity::Positive, ty::PredicatePolarity::Negative)
89 | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Positive) => {
90 return Err(NoSolution);
91 }
92 };
93
94 ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
95 let impl_args = ecx.fresh_args_for_item(impl_def_id.into());
96 ecx.record_impl_args(impl_args);
97 let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args);
98
99 ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
100 let where_clause_bounds = cx
101 .predicates_of(impl_def_id.into())
102 .iter_instantiated(cx, impl_args)
103 .map(|pred| goal.with(cx, pred));
104 ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
105
106 ecx.add_goals(
110 GoalSource::Misc,
111 cx.impl_super_outlives(impl_def_id)
112 .iter_instantiated(cx, impl_args)
113 .map(|pred| goal.with(cx, pred)),
114 );
115
116 then(ecx, maximal_certainty)
117 })
118 }
119
120 fn consider_error_guaranteed_candidate(
121 ecx: &mut EvalCtxt<'_, D>,
122 _guar: I::ErrorGuaranteed,
123 ) -> Result<Candidate<I>, NoSolution> {
124 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
125 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
126 }
127
128 fn fast_reject_assumption(
129 ecx: &mut EvalCtxt<'_, D>,
130 goal: Goal<I, Self>,
131 assumption: I::Clause,
132 ) -> Result<(), NoSolution> {
133 fn trait_def_id_matches<I: Interner>(
134 cx: I,
135 clause_def_id: I::TraitId,
136 goal_def_id: I::TraitId,
137 polarity: PredicatePolarity,
138 ) -> bool {
139 clause_def_id == goal_def_id
140 || (polarity == PredicatePolarity::Positive
145 && cx.is_trait_lang_item(clause_def_id, SolverTraitLangItem::Sized)
146 && cx.is_trait_lang_item(goal_def_id, SolverTraitLangItem::MetaSized))
147 }
148
149 if let Some(trait_clause) = assumption.as_trait_clause()
150 && trait_clause.polarity() == goal.predicate.polarity
151 && trait_def_id_matches(
152 ecx.cx(),
153 trait_clause.def_id(),
154 goal.predicate.def_id(),
155 goal.predicate.polarity,
156 )
157 && DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
158 goal.predicate.trait_ref.args,
159 trait_clause.skip_binder().trait_ref.args,
160 )
161 {
162 return Ok(());
163 } else {
164 Err(NoSolution)
165 }
166 }
167
168 fn match_assumption(
169 ecx: &mut EvalCtxt<'_, D>,
170 goal: Goal<I, Self>,
171 assumption: I::Clause,
172 then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
173 ) -> QueryResult<I> {
174 let trait_clause = assumption.as_trait_clause().unwrap();
175
176 if ecx.cx().is_trait_lang_item(goal.predicate.def_id(), SolverTraitLangItem::MetaSized)
182 && ecx.cx().is_trait_lang_item(trait_clause.def_id(), SolverTraitLangItem::Sized)
183 {
184 let meta_sized_clause =
185 trait_predicate_with_def_id(ecx.cx(), trait_clause, goal.predicate.def_id());
186 return Self::match_assumption(ecx, goal, meta_sized_clause, then);
187 }
188
189 let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
190 ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
191
192 then(ecx)
193 }
194
195 fn consider_auto_trait_candidate(
196 ecx: &mut EvalCtxt<'_, D>,
197 goal: Goal<I, Self>,
198 ) -> Result<Candidate<I>, NoSolution> {
199 let cx = ecx.cx();
200 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
201 return Err(NoSolution);
202 }
203
204 if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) {
205 return result;
206 }
207
208 if cx.trait_is_unsafe(goal.predicate.def_id())
211 && goal.predicate.self_ty().has_unsafe_fields()
212 {
213 return Err(NoSolution);
214 }
215
216 if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
232 debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id));
233 for item_bound in cx.item_self_bounds(opaque_ty.def_id).skip_binder() {
234 if item_bound
235 .as_trait_clause()
236 .is_some_and(|b| b.def_id() == goal.predicate.def_id())
237 {
238 return Err(NoSolution);
239 }
240 }
241 }
242
243 if let Some(cand) = ecx.try_stall_coroutine(goal.predicate.self_ty()) {
245 return cand;
246 }
247
248 ecx.probe_and_evaluate_goal_for_constituent_tys(
249 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
250 goal,
251 structural_traits::instantiate_constituent_tys_for_auto_trait,
252 )
253 }
254
255 fn consider_trait_alias_candidate(
256 ecx: &mut EvalCtxt<'_, D>,
257 goal: Goal<I, Self>,
258 ) -> Result<Candidate<I>, NoSolution> {
259 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
260 return Err(NoSolution);
261 }
262
263 let cx = ecx.cx();
264
265 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
266 let nested_obligations = cx
267 .predicates_of(goal.predicate.def_id().into())
268 .iter_instantiated(cx, goal.predicate.trait_ref.args)
269 .map(|p| goal.with(cx, p));
270 ecx.add_goals(GoalSource::Misc, nested_obligations);
276 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
277 })
278 }
279
280 fn consider_builtin_sizedness_candidates(
281 ecx: &mut EvalCtxt<'_, D>,
282 goal: Goal<I, Self>,
283 sizedness: SizedTraitKind,
284 ) -> Result<Candidate<I>, NoSolution> {
285 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
286 return Err(NoSolution);
287 }
288
289 ecx.probe_and_evaluate_goal_for_constituent_tys(
290 CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial),
291 goal,
292 |ecx, ty| {
293 structural_traits::instantiate_constituent_tys_for_sizedness_trait(
294 ecx, sizedness, ty,
295 )
296 },
297 )
298 }
299
300 fn consider_builtin_copy_clone_candidate(
301 ecx: &mut EvalCtxt<'_, D>,
302 goal: Goal<I, Self>,
303 ) -> Result<Candidate<I>, NoSolution> {
304 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
305 return Err(NoSolution);
306 }
307
308 if let Some(cand) = ecx.try_stall_coroutine(goal.predicate.self_ty()) {
310 return cand;
311 }
312
313 ecx.probe_and_evaluate_goal_for_constituent_tys(
314 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
315 goal,
316 structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
317 )
318 }
319
320 fn consider_builtin_fn_ptr_trait_candidate(
321 ecx: &mut EvalCtxt<'_, D>,
322 goal: Goal<I, Self>,
323 ) -> Result<Candidate<I>, NoSolution> {
324 let self_ty = goal.predicate.self_ty();
325 match goal.predicate.polarity {
326 ty::PredicatePolarity::Positive => {
328 if self_ty.is_fn_ptr() {
329 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
330 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
331 })
332 } else {
333 Err(NoSolution)
334 }
335 }
336 ty::PredicatePolarity::Negative => {
338 if !self_ty.is_fn_ptr() && self_ty.is_known_rigid() {
341 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
342 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
343 })
344 } else {
345 Err(NoSolution)
346 }
347 }
348 }
349 }
350
351 fn consider_builtin_fn_trait_candidates(
352 ecx: &mut EvalCtxt<'_, D>,
353 goal: Goal<I, Self>,
354 goal_kind: ty::ClosureKind,
355 ) -> Result<Candidate<I>, NoSolution> {
356 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
357 return Err(NoSolution);
358 }
359
360 let cx = ecx.cx();
361 let tupled_inputs_and_output =
362 match structural_traits::extract_tupled_inputs_and_output_from_callable(
363 cx,
364 goal.predicate.self_ty(),
365 goal_kind,
366 )? {
367 Some(a) => a,
368 None => {
369 return ecx.forced_ambiguity(MaybeCause::Ambiguity);
370 }
371 };
372
373 let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
376 ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output])
377 });
378
379 let pred = tupled_inputs_and_output
380 .map_bound(|(inputs, _)| {
381 ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
382 })
383 .upcast(cx);
384 Self::probe_and_consider_implied_clause(
385 ecx,
386 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
387 goal,
388 pred,
389 [(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))],
390 )
391 }
392
393 fn consider_builtin_async_fn_trait_candidates(
394 ecx: &mut EvalCtxt<'_, D>,
395 goal: Goal<I, Self>,
396 goal_kind: ty::ClosureKind,
397 ) -> Result<Candidate<I>, NoSolution> {
398 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
399 return Err(NoSolution);
400 }
401
402 let cx = ecx.cx();
403 let (tupled_inputs_and_output_and_coroutine, nested_preds) =
404 structural_traits::extract_tupled_inputs_and_output_from_async_callable(
405 cx,
406 goal.predicate.self_ty(),
407 goal_kind,
408 Region::new_static(cx),
410 )?;
411
412 let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
415 |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| {
416 ty::TraitRef::new(
417 cx,
418 cx.require_trait_lang_item(SolverTraitLangItem::Sized),
419 [output_coroutine_ty],
420 )
421 },
422 );
423
424 let pred = tupled_inputs_and_output_and_coroutine
425 .map_bound(|AsyncCallableRelevantTypes { tupled_inputs_ty, .. }| {
426 ty::TraitRef::new(
427 cx,
428 goal.predicate.def_id(),
429 [goal.predicate.self_ty(), tupled_inputs_ty],
430 )
431 })
432 .upcast(cx);
433 Self::probe_and_consider_implied_clause(
434 ecx,
435 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
436 goal,
437 pred,
438 [goal.with(cx, output_is_sized_pred)]
439 .into_iter()
440 .chain(nested_preds.into_iter().map(|pred| goal.with(cx, pred)))
441 .map(|goal| (GoalSource::ImplWhereBound, goal)),
442 )
443 }
444
445 fn consider_builtin_async_fn_kind_helper_candidate(
446 ecx: &mut EvalCtxt<'_, D>,
447 goal: Goal<I, Self>,
448 ) -> Result<Candidate<I>, NoSolution> {
449 let [closure_fn_kind_ty, goal_kind_ty] = *goal.predicate.trait_ref.args.as_slice() else {
450 panic!();
451 };
452
453 let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
454 return Err(NoSolution);
456 };
457 let goal_kind = goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap();
458 if closure_kind.extends(goal_kind) {
459 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
460 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
461 } else {
462 Err(NoSolution)
463 }
464 }
465
466 fn consider_builtin_tuple_candidate(
473 ecx: &mut EvalCtxt<'_, D>,
474 goal: Goal<I, Self>,
475 ) -> Result<Candidate<I>, NoSolution> {
476 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
477 return Err(NoSolution);
478 }
479
480 if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
481 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
482 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
483 } else {
484 Err(NoSolution)
485 }
486 }
487
488 fn consider_builtin_pointee_candidate(
489 ecx: &mut EvalCtxt<'_, D>,
490 goal: Goal<I, Self>,
491 ) -> Result<Candidate<I>, NoSolution> {
492 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
493 return Err(NoSolution);
494 }
495
496 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
497 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
498 }
499
500 fn consider_builtin_future_candidate(
501 ecx: &mut EvalCtxt<'_, D>,
502 goal: Goal<I, Self>,
503 ) -> Result<Candidate<I>, NoSolution> {
504 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
505 return Err(NoSolution);
506 }
507
508 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
509 return Err(NoSolution);
510 };
511
512 let cx = ecx.cx();
514 if !cx.coroutine_is_async(def_id) {
515 return Err(NoSolution);
516 }
517
518 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
522 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
523 }
524
525 fn consider_builtin_iterator_candidate(
526 ecx: &mut EvalCtxt<'_, D>,
527 goal: Goal<I, Self>,
528 ) -> Result<Candidate<I>, NoSolution> {
529 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
530 return Err(NoSolution);
531 }
532
533 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
534 return Err(NoSolution);
535 };
536
537 let cx = ecx.cx();
539 if !cx.coroutine_is_gen(def_id) {
540 return Err(NoSolution);
541 }
542
543 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
547 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
548 }
549
550 fn consider_builtin_fused_iterator_candidate(
551 ecx: &mut EvalCtxt<'_, D>,
552 goal: Goal<I, Self>,
553 ) -> Result<Candidate<I>, NoSolution> {
554 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
555 return Err(NoSolution);
556 }
557
558 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
559 return Err(NoSolution);
560 };
561
562 let cx = ecx.cx();
564 if !cx.coroutine_is_gen(def_id) {
565 return Err(NoSolution);
566 }
567
568 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
570 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
571 }
572
573 fn consider_builtin_async_iterator_candidate(
574 ecx: &mut EvalCtxt<'_, D>,
575 goal: Goal<I, Self>,
576 ) -> Result<Candidate<I>, NoSolution> {
577 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
578 return Err(NoSolution);
579 }
580
581 let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
582 return Err(NoSolution);
583 };
584
585 let cx = ecx.cx();
587 if !cx.coroutine_is_async_gen(def_id) {
588 return Err(NoSolution);
589 }
590
591 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
595 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
596 }
597
598 fn consider_builtin_coroutine_candidate(
599 ecx: &mut EvalCtxt<'_, D>,
600 goal: Goal<I, Self>,
601 ) -> Result<Candidate<I>, NoSolution> {
602 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
603 return Err(NoSolution);
604 }
605
606 let self_ty = goal.predicate.self_ty();
607 let ty::Coroutine(def_id, args) = self_ty.kind() else {
608 return Err(NoSolution);
609 };
610
611 let cx = ecx.cx();
613 if !cx.is_general_coroutine(def_id) {
614 return Err(NoSolution);
615 }
616
617 let coroutine = args.as_coroutine();
618 Self::probe_and_consider_implied_clause(
619 ecx,
620 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
621 goal,
622 ty::TraitRef::new(cx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()])
623 .upcast(cx),
624 [],
627 )
628 }
629
630 fn consider_builtin_discriminant_kind_candidate(
631 ecx: &mut EvalCtxt<'_, D>,
632 goal: Goal<I, Self>,
633 ) -> Result<Candidate<I>, NoSolution> {
634 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
635 return Err(NoSolution);
636 }
637
638 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
640 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
641 }
642
643 fn consider_builtin_destruct_candidate(
644 ecx: &mut EvalCtxt<'_, D>,
645 goal: Goal<I, Self>,
646 ) -> Result<Candidate<I>, NoSolution> {
647 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
648 return Err(NoSolution);
649 }
650
651 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
654 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
655 }
656
657 fn consider_builtin_transmute_candidate(
658 ecx: &mut EvalCtxt<'_, D>,
659 goal: Goal<I, Self>,
660 ) -> Result<Candidate<I>, NoSolution> {
661 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
662 return Err(NoSolution);
663 }
664
665 if goal.has_non_region_placeholders() {
667 return Err(NoSolution);
668 }
669
670 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
671 let assume = ecx.structurally_normalize_const(
672 goal.param_env,
673 goal.predicate.trait_ref.args.const_at(2),
674 )?;
675
676 let certainty = ecx.is_transmutable(
677 goal.predicate.trait_ref.args.type_at(0),
678 goal.predicate.trait_ref.args.type_at(1),
679 assume,
680 )?;
681 ecx.evaluate_added_goals_and_make_canonical_response(certainty)
682 })
683 }
684
685 fn consider_builtin_bikeshed_guaranteed_no_drop_candidate(
695 ecx: &mut EvalCtxt<'_, D>,
696 goal: Goal<I, Self>,
697 ) -> Result<Candidate<I>, NoSolution> {
698 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
699 return Err(NoSolution);
700 }
701
702 let cx = ecx.cx();
703 ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
704 let ty = goal.predicate.self_ty();
705 match ty.kind() {
706 ty::Ref(..) => {}
708 ty::Adt(def, _) if def.is_manually_drop() => {}
710 ty::Tuple(tys) => {
713 ecx.add_goals(
714 GoalSource::ImplWhereBound,
715 tys.iter().map(|elem_ty| {
716 goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty]))
717 }),
718 );
719 }
720 ty::Array(elem_ty, _) => {
721 ecx.add_goal(
722 GoalSource::ImplWhereBound,
723 goal.with(cx, ty::TraitRef::new(cx, goal.predicate.def_id(), [elem_ty])),
724 );
725 }
726
727 ty::FnDef(..)
731 | ty::FnPtr(..)
732 | ty::Error(_)
733 | ty::Uint(_)
734 | ty::Int(_)
735 | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
736 | ty::Bool
737 | ty::Float(_)
738 | ty::Char
739 | ty::RawPtr(..)
740 | ty::Never
741 | ty::Pat(..)
742 | ty::Dynamic(..)
743 | ty::Str
744 | ty::Slice(_)
745 | ty::Foreign(..)
746 | ty::Adt(..)
747 | ty::Alias(..)
748 | ty::Param(_)
749 | ty::Placeholder(..)
750 | ty::Closure(..)
751 | ty::CoroutineClosure(..)
752 | ty::Coroutine(..)
753 | ty::UnsafeBinder(_)
754 | ty::CoroutineWitness(..) => {
755 ecx.add_goal(
756 GoalSource::ImplWhereBound,
757 goal.with(
758 cx,
759 ty::TraitRef::new(
760 cx,
761 cx.require_trait_lang_item(SolverTraitLangItem::Copy),
762 [ty],
763 ),
764 ),
765 );
766 }
767
768 ty::Bound(..)
769 | ty::Infer(
770 ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
771 ) => {
772 panic!("unexpected type `{ty:?}`")
773 }
774 }
775
776 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
777 })
778 }
779
780 fn consider_structural_builtin_unsize_candidates(
788 ecx: &mut EvalCtxt<'_, D>,
789 goal: Goal<I, Self>,
790 ) -> Vec<Candidate<I>> {
791 if goal.predicate.polarity != ty::PredicatePolarity::Positive {
792 return vec![];
793 }
794
795 let result_to_single = |result| match result {
796 Ok(resp) => vec![resp],
797 Err(NoSolution) => vec![],
798 };
799
800 ecx.probe(|_| ProbeKind::UnsizeAssembly).enter(|ecx| {
801 let a_ty = goal.predicate.self_ty();
802 let Ok(b_ty) = ecx.structurally_normalize_ty(
805 goal.param_env,
806 goal.predicate.trait_ref.args.type_at(1),
807 ) else {
808 return vec![];
809 };
810
811 let goal = goal.with(ecx.cx(), (a_ty, b_ty));
812 match (a_ty.kind(), b_ty.kind()) {
813 (ty::Infer(ty::TyVar(..)), ..) => panic!("unexpected infer {a_ty:?} {b_ty:?}"),
814
815 (_, ty::Infer(ty::TyVar(..))) => {
816 result_to_single(ecx.forced_ambiguity(MaybeCause::Ambiguity))
817 }
818
819 (
821 ty::Dynamic(a_data, a_region, ty::Dyn),
822 ty::Dynamic(b_data, b_region, ty::Dyn),
823 ) => ecx.consider_builtin_dyn_upcast_candidates(
824 goal, a_data, a_region, b_data, b_region,
825 ),
826
827 (_, ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single(
829 ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data),
830 ),
831
832 (ty::Array(a_elem_ty, ..), ty::Slice(b_elem_ty)) => {
834 result_to_single(ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty))
835 }
836
837 (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args))
839 if a_def.is_struct() && a_def == b_def =>
840 {
841 result_to_single(
842 ecx.consider_builtin_struct_unsize(goal, a_def, a_args, b_args),
843 )
844 }
845
846 _ => vec![],
847 }
848 })
849 }
850}
851
852#[inline(always)]
858fn trait_predicate_with_def_id<I: Interner>(
859 cx: I,
860 clause: ty::Binder<I, ty::TraitPredicate<I>>,
861 did: I::TraitId,
862) -> I::Clause {
863 clause
864 .map_bound(|c| TraitPredicate {
865 trait_ref: TraitRef::new_from_args(cx, did, c.trait_ref.args),
866 polarity: c.polarity,
867 })
868 .upcast(cx)
869}
870
871impl<D, I> EvalCtxt<'_, D>
872where
873 D: SolverDelegate<Interner = I>,
874 I: Interner,
875{
876 fn consider_builtin_dyn_upcast_candidates(
886 &mut self,
887 goal: Goal<I, (I::Ty, I::Ty)>,
888 a_data: I::BoundExistentialPredicates,
889 a_region: I::Region,
890 b_data: I::BoundExistentialPredicates,
891 b_region: I::Region,
892 ) -> Vec<Candidate<I>> {
893 let cx = self.cx();
894 let Goal { predicate: (a_ty, _b_ty), .. } = goal;
895
896 let mut responses = vec![];
897 let b_principal_def_id = b_data.principal_def_id();
900 if a_data.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
901 responses.extend(self.consider_builtin_upcast_to_principal(
902 goal,
903 CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
904 a_data,
905 a_region,
906 b_data,
907 b_region,
908 a_data.principal(),
909 ));
910 } else if let Some(a_principal) = a_data.principal() {
911 for (idx, new_a_principal) in
912 elaborate::supertraits(self.cx(), a_principal.with_self_ty(cx, a_ty))
913 .enumerate()
914 .skip(1)
915 {
916 responses.extend(self.consider_builtin_upcast_to_principal(
917 goal,
918 CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting(idx)),
919 a_data,
920 a_region,
921 b_data,
922 b_region,
923 Some(new_a_principal.map_bound(|trait_ref| {
924 ty::ExistentialTraitRef::erase_self_ty(cx, trait_ref)
925 })),
926 ));
927 }
928 }
929
930 responses
931 }
932
933 fn consider_builtin_unsize_to_dyn_candidate(
934 &mut self,
935 goal: Goal<I, (I::Ty, I::Ty)>,
936 b_data: I::BoundExistentialPredicates,
937 b_region: I::Region,
938 ) -> Result<Candidate<I>, NoSolution> {
939 let cx = self.cx();
940 let Goal { predicate: (a_ty, _), .. } = goal;
941
942 if b_data.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) {
944 return Err(NoSolution);
945 }
946
947 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
948 ecx.add_goals(
951 GoalSource::ImplWhereBound,
952 b_data.iter().map(|pred| goal.with(cx, pred.with_self_ty(cx, a_ty))),
953 );
954
955 ecx.add_goal(
957 GoalSource::ImplWhereBound,
958 goal.with(
959 cx,
960 ty::TraitRef::new(
961 cx,
962 cx.require_trait_lang_item(SolverTraitLangItem::Sized),
963 [a_ty],
964 ),
965 ),
966 );
967
968 ecx.add_goal(GoalSource::Misc, goal.with(cx, ty::OutlivesPredicate(a_ty, b_region)));
970 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
971 })
972 }
973
974 fn consider_builtin_upcast_to_principal(
975 &mut self,
976 goal: Goal<I, (I::Ty, I::Ty)>,
977 source: CandidateSource<I>,
978 a_data: I::BoundExistentialPredicates,
979 a_region: I::Region,
980 b_data: I::BoundExistentialPredicates,
981 b_region: I::Region,
982 upcast_principal: Option<ty::Binder<I, ty::ExistentialTraitRef<I>>>,
983 ) -> Result<Candidate<I>, NoSolution> {
984 let param_env = goal.param_env;
985
986 let a_auto_traits: IndexSet<I::TraitId> = a_data
990 .auto_traits()
991 .into_iter()
992 .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
993 elaborate::supertrait_def_ids(self.cx(), principal_def_id)
994 .filter(|def_id| self.cx().trait_is_auto(*def_id))
995 }))
996 .collect();
997
998 let projection_may_match =
1003 |ecx: &mut EvalCtxt<'_, D>,
1004 source_projection: ty::Binder<I, ty::ExistentialProjection<I>>,
1005 target_projection: ty::Binder<I, ty::ExistentialProjection<I>>| {
1006 source_projection.item_def_id() == target_projection.item_def_id()
1007 && ecx
1008 .probe(|_| ProbeKind::ProjectionCompatibility)
1009 .enter(|ecx| -> Result<_, NoSolution> {
1010 ecx.enter_forall(target_projection, |ecx, target_projection| {
1011 let source_projection =
1012 ecx.instantiate_binder_with_infer(source_projection);
1013 ecx.eq(param_env, source_projection, target_projection)?;
1014 ecx.try_evaluate_added_goals()
1015 })
1016 })
1017 .is_ok()
1018 };
1019
1020 self.probe_trait_candidate(source).enter(|ecx| {
1021 for bound in b_data.iter() {
1022 match bound.skip_binder() {
1023 ty::ExistentialPredicate::Trait(target_principal) => {
1026 let source_principal = upcast_principal.unwrap();
1027 let target_principal = bound.rebind(target_principal);
1028 ecx.enter_forall(target_principal, |ecx, target_principal| {
1029 let source_principal =
1030 ecx.instantiate_binder_with_infer(source_principal);
1031 ecx.eq(param_env, source_principal, target_principal)?;
1032 ecx.try_evaluate_added_goals()
1033 })?;
1034 }
1035 ty::ExistentialPredicate::Projection(target_projection) => {
1041 let target_projection = bound.rebind(target_projection);
1042 let mut matching_projections =
1043 a_data.projection_bounds().into_iter().filter(|source_projection| {
1044 projection_may_match(ecx, *source_projection, target_projection)
1045 });
1046 let Some(source_projection) = matching_projections.next() else {
1047 return Err(NoSolution);
1048 };
1049 if matching_projections.next().is_some() {
1050 return ecx.evaluate_added_goals_and_make_canonical_response(
1051 Certainty::AMBIGUOUS,
1052 );
1053 }
1054 ecx.enter_forall(target_projection, |ecx, target_projection| {
1055 let source_projection =
1056 ecx.instantiate_binder_with_infer(source_projection);
1057 ecx.eq(param_env, source_projection, target_projection)?;
1058 ecx.try_evaluate_added_goals()
1059 })?;
1060 }
1061 ty::ExistentialPredicate::AutoTrait(def_id) => {
1063 if !a_auto_traits.contains(&def_id) {
1064 return Err(NoSolution);
1065 }
1066 }
1067 }
1068 }
1069
1070 ecx.add_goal(
1072 GoalSource::ImplWhereBound,
1073 Goal::new(ecx.cx(), param_env, ty::OutlivesPredicate(a_region, b_region)),
1074 );
1075
1076 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1077 })
1078 }
1079
1080 fn consider_builtin_array_unsize(
1089 &mut self,
1090 goal: Goal<I, (I::Ty, I::Ty)>,
1091 a_elem_ty: I::Ty,
1092 b_elem_ty: I::Ty,
1093 ) -> Result<Candidate<I>, NoSolution> {
1094 self.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
1095 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
1096 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
1097 }
1098
1099 fn consider_builtin_struct_unsize(
1113 &mut self,
1114 goal: Goal<I, (I::Ty, I::Ty)>,
1115 def: I::AdtDef,
1116 a_args: I::GenericArgs,
1117 b_args: I::GenericArgs,
1118 ) -> Result<Candidate<I>, NoSolution> {
1119 let cx = self.cx();
1120 let Goal { predicate: (_a_ty, b_ty), .. } = goal;
1121
1122 let unsizing_params = cx.unsizing_params_for_adt(def.def_id());
1123 if unsizing_params.is_empty() {
1126 return Err(NoSolution);
1127 }
1128
1129 let tail_field_ty = def.struct_tail_ty(cx).unwrap();
1130
1131 let a_tail_ty = tail_field_ty.instantiate(cx, a_args);
1132 let b_tail_ty = tail_field_ty.instantiate(cx, b_args);
1133
1134 let new_a_args = cx.mk_args_from_iter(a_args.iter().enumerate().map(|(i, a)| {
1138 if unsizing_params.contains(i as u32) { b_args.get(i).unwrap() } else { a }
1139 }));
1140 let unsized_a_ty = Ty::new_adt(cx, def, new_a_args);
1141
1142 self.eq(goal.param_env, unsized_a_ty, b_ty)?;
1145 self.add_goal(
1146 GoalSource::ImplWhereBound,
1147 goal.with(
1148 cx,
1149 ty::TraitRef::new(
1150 cx,
1151 cx.require_trait_lang_item(SolverTraitLangItem::Unsize),
1152 [a_tail_ty, b_tail_ty],
1153 ),
1154 ),
1155 );
1156 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
1157 .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
1158 }
1159
1160 fn disqualify_auto_trait_candidate_due_to_possible_impl(
1165 &mut self,
1166 goal: Goal<I, TraitPredicate<I>>,
1167 ) -> Option<Result<Candidate<I>, NoSolution>> {
1168 let self_ty = goal.predicate.self_ty();
1169 let check_impls = || {
1170 let mut disqualifying_impl = None;
1171 self.cx().for_each_relevant_impl(
1172 goal.predicate.def_id(),
1173 goal.predicate.self_ty(),
1174 |impl_def_id| {
1175 disqualifying_impl = Some(impl_def_id);
1176 },
1177 );
1178 if let Some(def_id) = disqualifying_impl {
1179 trace!(?def_id, ?goal, "disqualified auto-trait implementation");
1180 return Some(Err(NoSolution));
1183 } else {
1184 None
1185 }
1186 };
1187
1188 match self_ty.kind() {
1189 ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
1195 Some(self.forced_ambiguity(MaybeCause::Ambiguity))
1196 }
1197
1198 ty::Foreign(..) if self.cx().is_default_trait(goal.predicate.def_id()) => check_impls(),
1201
1202 ty::Dynamic(..)
1205 | ty::Param(..)
1206 | ty::Foreign(..)
1207 | ty::Alias(ty::Projection | ty::Free | ty::Inherent, ..)
1208 | ty::Placeholder(..) => Some(Err(NoSolution)),
1209
1210 ty::Infer(_) | ty::Bound(_, _) => panic!("unexpected type `{self_ty:?}`"),
1211
1212 ty::Coroutine(def_id, _)
1216 if self
1217 .cx()
1218 .is_trait_lang_item(goal.predicate.def_id(), SolverTraitLangItem::Unpin) =>
1219 {
1220 match self.cx().coroutine_movability(def_id) {
1221 Movability::Static => Some(Err(NoSolution)),
1222 Movability::Movable => Some(
1223 self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
1224 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1225 }),
1226 ),
1227 }
1228 }
1229
1230 ty::Alias(..) => None,
1235
1236 ty::Bool
1243 | ty::Char
1244 | ty::Int(_)
1245 | ty::Uint(_)
1246 | ty::Float(_)
1247 | ty::Str
1248 | ty::Array(_, _)
1249 | ty::Pat(_, _)
1250 | ty::Slice(_)
1251 | ty::RawPtr(_, _)
1252 | ty::Ref(_, _, _)
1253 | ty::FnDef(_, _)
1254 | ty::FnPtr(..)
1255 | ty::Closure(..)
1256 | ty::CoroutineClosure(..)
1257 | ty::Coroutine(_, _)
1258 | ty::CoroutineWitness(..)
1259 | ty::Never
1260 | ty::Tuple(_)
1261 | ty::Adt(_, _)
1262 | ty::UnsafeBinder(_) => check_impls(),
1263 ty::Error(_) => None,
1264 }
1265 }
1266
1267 fn probe_and_evaluate_goal_for_constituent_tys(
1272 &mut self,
1273 source: CandidateSource<I>,
1274 goal: Goal<I, TraitPredicate<I>>,
1275 constituent_tys: impl Fn(
1276 &EvalCtxt<'_, D>,
1277 I::Ty,
1278 ) -> Result<ty::Binder<I, Vec<I::Ty>>, NoSolution>,
1279 ) -> Result<Candidate<I>, NoSolution> {
1280 self.probe_trait_candidate(source).enter(|ecx| {
1281 let goals =
1282 ecx.enter_forall(constituent_tys(ecx, goal.predicate.self_ty())?, |ecx, tys| {
1283 tys.into_iter()
1284 .map(|ty| {
1285 goal.with(ecx.cx(), goal.predicate.with_replaced_self_ty(ecx.cx(), ty))
1286 })
1287 .collect::<Vec<_>>()
1288 });
1289 ecx.add_goals(GoalSource::ImplWhereBound, goals);
1290 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
1291 })
1292 }
1293}
1294
1295#[derive(Debug, Clone, Copy)]
1306pub(super) enum TraitGoalProvenVia {
1307 Misc,
1313 ParamEnv,
1314 AliasBound,
1315}
1316
1317impl<D, I> EvalCtxt<'_, D>
1318where
1319 D: SolverDelegate<Interner = I>,
1320 I: Interner,
1321{
1322 pub(super) fn unsound_prefer_builtin_dyn_impl(&mut self, candidates: &mut Vec<Candidate<I>>) {
1335 match self.typing_mode() {
1336 TypingMode::Coherence => return,
1337 TypingMode::Analysis { .. }
1338 | TypingMode::Borrowck { .. }
1339 | TypingMode::PostBorrowckAnalysis { .. }
1340 | TypingMode::PostAnalysis => {}
1341 }
1342
1343 if candidates
1344 .iter()
1345 .find(|c| {
1346 matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Object(_)))
1347 })
1348 .is_some_and(|c| has_only_region_constraints(c.result))
1349 {
1350 candidates.retain(|c| {
1351 if matches!(c.source, CandidateSource::Impl(_)) {
1352 debug!(?c, "unsoundly dropping impl in favor of builtin dyn-candidate");
1353 false
1354 } else {
1355 true
1356 }
1357 });
1358 }
1359 }
1360
1361 #[instrument(level = "debug", skip(self), ret)]
1362 pub(super) fn merge_trait_candidates(
1363 &mut self,
1364 mut candidates: Vec<Candidate<I>>,
1365 failed_candidate_info: FailedCandidateInfo,
1366 ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
1367 if let TypingMode::Coherence = self.typing_mode() {
1368 return if let Some((response, _)) = self.try_merge_candidates(&candidates) {
1369 Ok((response, Some(TraitGoalProvenVia::Misc)))
1370 } else {
1371 self.flounder(&candidates).map(|r| (r, None))
1372 };
1373 }
1374
1375 let mut trivial_builtin_impls = candidates.iter().filter(|c| {
1380 matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))
1381 });
1382 if let Some(candidate) = trivial_builtin_impls.next() {
1383 assert!(trivial_builtin_impls.next().is_none());
1386 return Ok((candidate.result, Some(TraitGoalProvenVia::Misc)));
1387 }
1388
1389 let has_non_global_where_bounds = candidates
1392 .iter()
1393 .any(|c| matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)));
1394 if has_non_global_where_bounds {
1395 let where_bounds: Vec<_> = candidates
1396 .extract_if(.., |c| matches!(c.source, CandidateSource::ParamEnv(_)))
1397 .collect();
1398 if let Some((response, info)) = self.try_merge_candidates(&where_bounds) {
1399 match info {
1400 MergeCandidateInfo::AlwaysApplicable(i) => {
1416 for (j, c) in where_bounds.into_iter().enumerate() {
1417 if i != j {
1418 self.ignore_candidate_head_usages(c.head_usages)
1419 }
1420 }
1421 self.ignore_candidate_head_usages(
1425 failed_candidate_info.param_env_head_usages,
1426 );
1427 }
1428 MergeCandidateInfo::EqualResponse => {}
1429 }
1430 return Ok((response, Some(TraitGoalProvenVia::ParamEnv)));
1431 } else {
1432 return Ok((self.bail_with_ambiguity(&where_bounds), None));
1433 };
1434 }
1435
1436 if candidates.iter().any(|c| matches!(c.source, CandidateSource::AliasBound)) {
1437 let alias_bounds: Vec<_> = candidates
1438 .extract_if(.., |c| matches!(c.source, CandidateSource::AliasBound))
1439 .collect();
1440 return if let Some((response, _)) = self.try_merge_candidates(&alias_bounds) {
1441 Ok((response, Some(TraitGoalProvenVia::AliasBound)))
1442 } else {
1443 Ok((self.bail_with_ambiguity(&alias_bounds), None))
1444 };
1445 }
1446
1447 self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates);
1448 self.unsound_prefer_builtin_dyn_impl(&mut candidates);
1449
1450 let proven_via = if candidates
1455 .iter()
1456 .all(|c| matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::Global)))
1457 {
1458 TraitGoalProvenVia::ParamEnv
1459 } else {
1460 candidates
1461 .retain(|c| !matches!(c.source, CandidateSource::ParamEnv(ParamEnvSource::Global)));
1462 TraitGoalProvenVia::Misc
1463 };
1464
1465 if let Some((response, _)) = self.try_merge_candidates(&candidates) {
1466 Ok((response, Some(proven_via)))
1467 } else {
1468 self.flounder(&candidates).map(|r| (r, None))
1469 }
1470 }
1471
1472 #[instrument(level = "trace", skip(self))]
1473 pub(super) fn compute_trait_goal(
1474 &mut self,
1475 goal: Goal<I, TraitPredicate<I>>,
1476 ) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
1477 let (candidates, failed_candidate_info) =
1478 self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
1479 self.merge_trait_candidates(candidates, failed_candidate_info)
1480 }
1481
1482 fn try_stall_coroutine(&mut self, self_ty: I::Ty) -> Option<Result<Candidate<I>, NoSolution>> {
1483 if let ty::Coroutine(def_id, _) = self_ty.kind() {
1484 match self.typing_mode() {
1485 TypingMode::Analysis {
1486 defining_opaque_types_and_generators: stalled_generators,
1487 } => {
1488 if def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id))
1489 {
1490 return Some(self.forced_ambiguity(MaybeCause::Ambiguity));
1491 }
1492 }
1493 TypingMode::Coherence
1494 | TypingMode::PostAnalysis
1495 | TypingMode::Borrowck { defining_opaque_types: _ }
1496 | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => {}
1497 }
1498 }
1499
1500 None
1501 }
1502}