]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_trait_selection/src/solve/project_goals.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / solve / project_goals.rs
CommitLineData
353b0b11 1use crate::traits::specialization_graph;
9c376795 2
353b0b11
FG
3use super::assembly::{self, structural_traits};
4use super::EvalCtxt;
9c376795
FG
5use rustc_errors::ErrorGuaranteed;
6use rustc_hir::def::DefKind;
7use rustc_hir::def_id::DefId;
9ffffee4 8use rustc_hir::LangItem;
9c376795
FG
9use rustc_infer::traits::query::NoSolution;
10use rustc_infer::traits::specialization_graph::LeafDef;
11use rustc_infer::traits::Reveal;
353b0b11 12use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
9c376795 13use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
9ffffee4 14use rustc_middle::ty::ProjectionPredicate;
9c376795 15use rustc_middle::ty::{self, Ty, TyCtxt};
9ffffee4
FG
16use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
17use rustc_span::{sym, DUMMY_SP};
9c376795
FG
18
19impl<'tcx> EvalCtxt<'_, 'tcx> {
353b0b11 20 #[instrument(level = "debug", skip(self), ret)]
9c376795
FG
21 pub(super) fn compute_projection_goal(
22 &mut self,
23 goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
24 ) -> QueryResult<'tcx> {
25 // To only compute normalization once for each projection we only
26 // normalize if the expected term is an unconstrained inference variable.
27 //
9ffffee4
FG
28 // E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal
29 // `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for
9c376795
FG
30 // `U` and equate it with `u32`. This means that we don't need a separate
31 // projection cache in the solver.
32 if self.term_is_fully_unconstrained(goal) {
33 let candidates = self.assemble_and_evaluate_candidates(goal);
353b0b11 34 self.merge_candidates(candidates)
9c376795 35 } else {
353b0b11
FG
36 self.set_normalizes_to_hack_goal(goal);
37 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
9c376795
FG
38 }
39 }
9c376795
FG
40}
41
42impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
43 fn self_ty(self) -> Ty<'tcx> {
44 self.self_ty()
45 }
46
353b0b11
FG
47 fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
48 self.projection_ty.trait_ref(tcx)
49 }
50
9c376795
FG
51 fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
52 self.with_self_ty(tcx, self_ty)
53 }
54
55 fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
56 self.trait_def_id(tcx)
57 }
58
9ffffee4
FG
59 fn consider_implied_clause(
60 ecx: &mut EvalCtxt<'_, 'tcx>,
61 goal: Goal<'tcx, Self>,
62 assumption: ty::Predicate<'tcx>,
63 requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
64 ) -> QueryResult<'tcx> {
65 if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
66 && poly_projection_pred.projection_def_id() == goal.predicate.def_id()
67 {
68 ecx.probe(|ecx| {
69 let assumption_projection_pred =
70 ecx.instantiate_binder_with_infer(poly_projection_pred);
353b0b11 71 ecx.eq(
9ffffee4
FG
72 goal.param_env,
73 goal.predicate.projection_ty,
74 assumption_projection_pred.projection_ty,
75 )?;
353b0b11
FG
76 ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)?;
77 ecx.add_goals(requirements);
78 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
9ffffee4
FG
79 })
80 } else {
81 Err(NoSolution)
82 }
83 }
84
85 fn consider_object_bound_candidate(
86 ecx: &mut EvalCtxt<'_, 'tcx>,
87 goal: Goal<'tcx, Self>,
88 assumption: ty::Predicate<'tcx>,
89 ) -> QueryResult<'tcx> {
90 if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
91 && poly_projection_pred.projection_def_id() == goal.predicate.def_id()
92 {
93 ecx.probe(|ecx| {
353b0b11
FG
94 let tcx = ecx.tcx();
95
9ffffee4
FG
96 let assumption_projection_pred =
97 ecx.instantiate_binder_with_infer(poly_projection_pred);
353b0b11 98 ecx.eq(
9ffffee4
FG
99 goal.param_env,
100 goal.predicate.projection_ty,
101 assumption_projection_pred.projection_ty,
102 )?;
103
9ffffee4
FG
104 let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
105 bug!("expected object type in `consider_object_bound_candidate`");
106 };
353b0b11 107 ecx.add_goals(
9ffffee4 108 structural_traits::predicates_for_object_candidate(
353b0b11 109 &ecx,
9ffffee4
FG
110 goal.param_env,
111 goal.predicate.projection_ty.trait_ref(tcx),
112 bounds,
113 )
114 .into_iter()
115 .map(|pred| goal.with(tcx, pred)),
116 );
353b0b11
FG
117 ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)?;
118 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
9ffffee4
FG
119 })
120 } else {
121 Err(NoSolution)
122 }
123 }
124
9c376795
FG
125 fn consider_impl_candidate(
126 ecx: &mut EvalCtxt<'_, 'tcx>,
127 goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
128 impl_def_id: DefId,
129 ) -> QueryResult<'tcx> {
130 let tcx = ecx.tcx();
131
132 let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx);
133 let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
353b0b11
FG
134 let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
135 if !drcx.substs_refs_may_unify(goal_trait_ref.substs, impl_trait_ref.skip_binder().substs) {
9c376795
FG
136 return Err(NoSolution);
137 }
138
9ffffee4
FG
139 ecx.probe(|ecx| {
140 let impl_substs = ecx.fresh_substs_for_item(impl_def_id);
9c376795
FG
141 let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
142
353b0b11
FG
143 ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?;
144
9c376795
FG
145 let where_clause_bounds = tcx
146 .predicates_of(impl_def_id)
147 .instantiate(tcx, impl_substs)
148 .predicates
149 .into_iter()
150 .map(|pred| goal.with(tcx, pred));
353b0b11 151 ecx.add_goals(where_clause_bounds);
9c376795
FG
152
153 // In case the associated item is hidden due to specialization, we have to
154 // return ambiguity this would otherwise be incomplete, resulting in
155 // unsoundness during coherence (#105782).
156 let Some(assoc_def) = fetch_eligible_assoc_item_def(
353b0b11 157 ecx,
9c376795
FG
158 goal.param_env,
159 goal_trait_ref,
160 goal.predicate.def_id(),
161 impl_def_id
162 )? else {
353b0b11 163 return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
9c376795
FG
164 };
165
166 if !assoc_def.item.defaultness(tcx).has_value() {
167 tcx.sess.delay_span_bug(
168 tcx.def_span(assoc_def.item.def_id),
169 "missing value for assoc item in impl",
170 );
171 }
172
173 // Getting the right substitutions here is complex, e.g. given:
174 // - a goal `<Vec<u32> as Trait<i32>>::Assoc<u64>`
175 // - the applicable impl `impl<T> Trait<i32> for Vec<T>`
176 // - and the impl which defines `Assoc` being `impl<T, U> Trait<U> for Vec<T>`
177 //
178 // We first rebase the goal substs onto the impl, going from `[Vec<u32>, i32, u64]`
179 // to `[u32, u64]`.
180 //
181 // And then map these substs to the substs of the defining impl of `Assoc`, going
182 // from `[u32, u64]` to `[u32, i32, u64]`.
183 let impl_substs_with_gat = goal.predicate.projection_ty.substs.rebase_onto(
184 tcx,
185 goal_trait_ref.def_id,
186 impl_substs,
187 );
353b0b11 188 let substs = ecx.translate_substs(
9c376795
FG
189 goal.param_env,
190 impl_def_id,
191 impl_substs_with_gat,
192 assoc_def.defining_node,
193 );
194
195 // Finally we construct the actual value of the associated type.
196 let is_const = matches!(tcx.def_kind(assoc_def.item.def_id), DefKind::AssocConst);
9ffffee4 197 let ty = tcx.type_of(assoc_def.item.def_id);
9c376795
FG
198 let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const {
199 let identity_substs =
200 ty::InternalSubsts::identity_for_item(tcx, assoc_def.item.def_id);
201 let did = ty::WithOptConstParam::unknown(assoc_def.item.def_id);
202 let kind =
203 ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new(did, identity_substs));
204 ty.map_bound(|ty| tcx.mk_const(kind, ty).into())
205 } else {
206 ty.map_bound(|ty| ty.into())
207 };
208
353b0b11
FG
209 ecx.eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs))?;
210 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
9c376795
FG
211 })
212 }
213
9c376795
FG
214 fn consider_auto_trait_candidate(
215 _ecx: &mut EvalCtxt<'_, 'tcx>,
216 goal: Goal<'tcx, Self>,
217 ) -> QueryResult<'tcx> {
218 bug!("auto traits do not have associated types: {:?}", goal);
219 }
220
221 fn consider_trait_alias_candidate(
222 _ecx: &mut EvalCtxt<'_, 'tcx>,
223 goal: Goal<'tcx, Self>,
224 ) -> QueryResult<'tcx> {
225 bug!("trait aliases do not have associated types: {:?}", goal);
226 }
227
228 fn consider_builtin_sized_candidate(
229 _ecx: &mut EvalCtxt<'_, 'tcx>,
230 goal: Goal<'tcx, Self>,
231 ) -> QueryResult<'tcx> {
232 bug!("`Sized` does not have an associated type: {:?}", goal);
233 }
234
235 fn consider_builtin_copy_clone_candidate(
236 _ecx: &mut EvalCtxt<'_, 'tcx>,
237 goal: Goal<'tcx, Self>,
238 ) -> QueryResult<'tcx> {
239 bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
240 }
241
9ffffee4 242 fn consider_builtin_pointer_like_candidate(
9c376795
FG
243 _ecx: &mut EvalCtxt<'_, 'tcx>,
244 goal: Goal<'tcx, Self>,
245 ) -> QueryResult<'tcx> {
9ffffee4 246 bug!("`PointerLike` does not have an associated type: {:?}", goal);
9c376795
FG
247 }
248
353b0b11
FG
249 fn consider_builtin_fn_ptr_trait_candidate(
250 _ecx: &mut EvalCtxt<'_, 'tcx>,
251 goal: Goal<'tcx, Self>,
252 ) -> QueryResult<'tcx> {
253 bug!("`FnPtr` does not have an associated type: {:?}", goal);
254 }
255
9c376795
FG
256 fn consider_builtin_fn_trait_candidates(
257 ecx: &mut EvalCtxt<'_, 'tcx>,
258 goal: Goal<'tcx, Self>,
259 goal_kind: ty::ClosureKind,
260 ) -> QueryResult<'tcx> {
9ffffee4 261 let tcx = ecx.tcx();
353b0b11
FG
262 let tupled_inputs_and_output =
263 match structural_traits::extract_tupled_inputs_and_output_from_callable(
264 tcx,
265 goal.predicate.self_ty(),
266 goal_kind,
267 )? {
268 Some(tupled_inputs_and_output) => tupled_inputs_and_output,
269 None => {
270 return ecx
271 .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
272 }
273 };
9ffffee4
FG
274 let output_is_sized_pred = tupled_inputs_and_output
275 .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
276
277 let pred = tupled_inputs_and_output
278 .map_bound(|(inputs, output)| ty::ProjectionPredicate {
279 projection_ty: tcx
280 .mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]),
281 term: output.into(),
282 })
283 .to_predicate(tcx);
284 // A built-in `Fn` impl only holds if the output is sized.
285 // (FIXME: technically we only need to check this if the type is a fn ptr...)
286 Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)])
9c376795
FG
287 }
288
289 fn consider_builtin_tuple_candidate(
290 _ecx: &mut EvalCtxt<'_, 'tcx>,
291 goal: Goal<'tcx, Self>,
292 ) -> QueryResult<'tcx> {
293 bug!("`Tuple` does not have an associated type: {:?}", goal);
294 }
9ffffee4
FG
295
296 fn consider_builtin_pointee_candidate(
297 ecx: &mut EvalCtxt<'_, 'tcx>,
298 goal: Goal<'tcx, Self>,
299 ) -> QueryResult<'tcx> {
300 let tcx = ecx.tcx();
301 ecx.probe(|ecx| {
302 let metadata_ty = match goal.predicate.self_ty().kind() {
303 ty::Bool
304 | ty::Char
305 | ty::Int(..)
306 | ty::Uint(..)
307 | ty::Float(..)
308 | ty::Array(..)
309 | ty::RawPtr(..)
310 | ty::Ref(..)
311 | ty::FnDef(..)
312 | ty::FnPtr(..)
313 | ty::Closure(..)
314 | ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
315 | ty::Generator(..)
316 | ty::GeneratorWitness(..)
317 | ty::GeneratorWitnessMIR(..)
318 | ty::Never
319 | ty::Foreign(..) => tcx.types.unit,
320
321 ty::Error(e) => tcx.ty_error(*e),
322
323 ty::Str | ty::Slice(_) => tcx.types.usize,
324
325 ty::Dynamic(_, _, _) => {
326 let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
327 tcx.type_of(dyn_metadata)
328 .subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())])
329 }
330
331 ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
332 // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints.
333 let sized_predicate = ty::Binder::dummy(tcx.at(DUMMY_SP).mk_trait_ref(
334 LangItem::Sized,
335 [ty::GenericArg::from(goal.predicate.self_ty())],
336 ));
353b0b11
FG
337 ecx.add_goal(goal.with(tcx, sized_predicate));
338 tcx.types.unit
9ffffee4
FG
339 }
340
341 ty::Adt(def, substs) if def.is_struct() => {
353b0b11 342 match def.non_enum_variant().fields.raw.last() {
9ffffee4
FG
343 None => tcx.types.unit,
344 Some(field_def) => {
345 let self_ty = field_def.ty(tcx, substs);
353b0b11 346 ecx.add_goal(goal.with(
9ffffee4
FG
347 tcx,
348 ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)),
353b0b11
FG
349 ));
350 return ecx
351 .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
9ffffee4
FG
352 }
353 }
354 }
355 ty::Adt(_, _) => tcx.types.unit,
356
357 ty::Tuple(elements) => match elements.last() {
358 None => tcx.types.unit,
359 Some(&self_ty) => {
353b0b11 360 ecx.add_goal(goal.with(
9ffffee4
FG
361 tcx,
362 ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)),
353b0b11
FG
363 ));
364 return ecx
365 .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
9ffffee4
FG
366 }
367 },
368
369 ty::Infer(
370 ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
371 )
372 | ty::Bound(..) => bug!(
373 "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
374 goal.predicate.self_ty()
375 ),
376 };
377
353b0b11
FG
378 ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into())?;
379 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
9ffffee4
FG
380 })
381 }
382
383 fn consider_builtin_future_candidate(
384 ecx: &mut EvalCtxt<'_, 'tcx>,
385 goal: Goal<'tcx, Self>,
386 ) -> QueryResult<'tcx> {
387 let self_ty = goal.predicate.self_ty();
388 let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
389 return Err(NoSolution);
390 };
391
392 // Generators are not futures unless they come from `async` desugaring
393 let tcx = ecx.tcx();
394 if !tcx.generator_is_async(def_id) {
395 return Err(NoSolution);
396 }
397
398 let term = substs.as_generator().return_ty().into();
399
400 Self::consider_implied_clause(
401 ecx,
402 goal,
403 ty::Binder::dummy(ty::ProjectionPredicate {
404 projection_ty: ecx.tcx().mk_alias_ty(goal.predicate.def_id(), [self_ty]),
405 term,
406 })
407 .to_predicate(tcx),
408 // Technically, we need to check that the future type is Sized,
409 // but that's already proven by the generator being WF.
410 [],
411 )
412 }
413
414 fn consider_builtin_generator_candidate(
415 ecx: &mut EvalCtxt<'_, 'tcx>,
416 goal: Goal<'tcx, Self>,
417 ) -> QueryResult<'tcx> {
418 let self_ty = goal.predicate.self_ty();
419 let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
420 return Err(NoSolution);
421 };
422
423 // `async`-desugared generators do not implement the generator trait
424 let tcx = ecx.tcx();
425 if tcx.generator_is_async(def_id) {
426 return Err(NoSolution);
427 }
428
429 let generator = substs.as_generator();
430
431 let name = tcx.associated_item(goal.predicate.def_id()).name;
432 let term = if name == sym::Return {
433 generator.return_ty().into()
434 } else if name == sym::Yield {
435 generator.yield_ty().into()
436 } else {
437 bug!("unexpected associated item `<{self_ty} as Generator>::{name}`")
438 };
439
440 Self::consider_implied_clause(
441 ecx,
442 goal,
443 ty::Binder::dummy(ty::ProjectionPredicate {
444 projection_ty: ecx
445 .tcx()
446 .mk_alias_ty(goal.predicate.def_id(), [self_ty, generator.resume_ty()]),
447 term,
448 })
449 .to_predicate(tcx),
450 // Technically, we need to check that the future type is Sized,
451 // but that's already proven by the generator being WF.
452 [],
453 )
454 }
455
456 fn consider_builtin_unsize_candidate(
457 _ecx: &mut EvalCtxt<'_, 'tcx>,
458 goal: Goal<'tcx, Self>,
459 ) -> QueryResult<'tcx> {
460 bug!("`Unsize` does not have an associated type: {:?}", goal);
461 }
462
463 fn consider_builtin_dyn_upcast_candidates(
464 _ecx: &mut EvalCtxt<'_, 'tcx>,
465 goal: Goal<'tcx, Self>,
353b0b11 466 ) -> Vec<CanonicalResponse<'tcx>> {
9ffffee4
FG
467 bug!("`Unsize` does not have an associated type: {:?}", goal);
468 }
469
470 fn consider_builtin_discriminant_kind_candidate(
471 ecx: &mut EvalCtxt<'_, 'tcx>,
472 goal: Goal<'tcx, Self>,
473 ) -> QueryResult<'tcx> {
353b0b11
FG
474 let self_ty = goal.predicate.self_ty();
475 let discriminant_ty = match *self_ty.kind() {
476 ty::Bool
477 | ty::Char
478 | ty::Int(..)
479 | ty::Uint(..)
480 | ty::Float(..)
481 | ty::Array(..)
482 | ty::RawPtr(..)
483 | ty::Ref(..)
484 | ty::FnDef(..)
485 | ty::FnPtr(..)
486 | ty::Closure(..)
487 | ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
488 | ty::Generator(..)
489 | ty::GeneratorWitness(..)
490 | ty::GeneratorWitnessMIR(..)
491 | ty::Never
492 | ty::Foreign(..)
493 | ty::Adt(_, _)
494 | ty::Str
495 | ty::Slice(_)
496 | ty::Dynamic(_, _, _)
497 | ty::Tuple(_)
498 | ty::Error(_) => self_ty.discriminant_ty(ecx.tcx()),
499
500 // We do not call `Ty::discriminant_ty` on alias, param, or placeholder
501 // types, which return `<self_ty as DiscriminantKind>::Discriminant`
502 // (or ICE in the case of placeholders). Projecting a type to itself
503 // is never really productive.
504 ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
505 return Err(NoSolution);
506 }
507
508 ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
509 | ty::Bound(..) => bug!(
510 "unexpected self ty `{:?}` when normalizing `<T as DiscriminantKind>::Discriminant`",
511 goal.predicate.self_ty()
512 ),
513 };
514
515 ecx.probe(|ecx| {
516 ecx.eq(goal.param_env, goal.predicate.term, discriminant_ty.into())?;
517 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
518 })
519 }
520
521 fn consider_builtin_destruct_candidate(
522 _ecx: &mut EvalCtxt<'_, 'tcx>,
523 goal: Goal<'tcx, Self>,
524 ) -> QueryResult<'tcx> {
525 bug!("`Destruct` does not have an associated type: {:?}", goal);
526 }
527
528 fn consider_builtin_transmute_candidate(
529 _ecx: &mut EvalCtxt<'_, 'tcx>,
530 goal: Goal<'tcx, Self>,
531 ) -> QueryResult<'tcx> {
532 bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal)
9ffffee4 533 }
9c376795
FG
534}
535
536/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
537///
538/// FIXME: We should merge these 3 implementations as it's likely that they otherwise
539/// diverge.
353b0b11 540#[instrument(level = "debug", skip(ecx, param_env), ret)]
9c376795 541fn fetch_eligible_assoc_item_def<'tcx>(
353b0b11 542 ecx: &EvalCtxt<'_, 'tcx>,
9c376795
FG
543 param_env: ty::ParamEnv<'tcx>,
544 goal_trait_ref: ty::TraitRef<'tcx>,
545 trait_assoc_def_id: DefId,
546 impl_def_id: DefId,
547) -> Result<Option<LeafDef>, NoSolution> {
353b0b11 548 let node_item = specialization_graph::assoc_def(ecx.tcx(), impl_def_id, trait_assoc_def_id)
9c376795
FG
549 .map_err(|ErrorGuaranteed { .. }| NoSolution)?;
550
551 let eligible = if node_item.is_final() {
552 // Non-specializable items are always projectable.
553 true
554 } else {
555 // Only reveal a specializable default if we're past type-checking
556 // and the obligation is monomorphic, otherwise passes such as
557 // transmute checking and polymorphic MIR optimizations could
558 // get a result which isn't correct for all monomorphizations.
559 if param_env.reveal() == Reveal::All {
353b0b11 560 let poly_trait_ref = ecx.resolve_vars_if_possible(goal_trait_ref);
9c376795
FG
561 !poly_trait_ref.still_further_specializable()
562 } else {
563 debug!(?node_item.item.def_id, "not eligible due to default");
564 false
565 }
566 };
567
568 if eligible { Ok(Some(node_item)) } else { Ok(None) }
569}