@@ -30,10 +30,14 @@ use rustc_errors::ErrorGuaranteed;
30
30
use rustc_hir as hir;
31
31
use rustc_hir::def_id::DefId;
32
32
use rustc_hir::lang_items::LangItem;
33
+ use rustc_infer::traits::TraitEngineExt as _;
33
34
use rustc_middle::ty::fold::TypeFoldable;
34
35
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
35
36
use rustc_middle::ty::visit::TypeVisitable;
36
- use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
37
+ use rustc_middle::ty::{
38
+ self, DefIdTree, GenericParamDefKind, Subst, ToPredicate, Ty, TyCtxt, TypeSuperVisitable,
39
+ VtblEntry,
40
+ };
37
41
use rustc_span::{sym, Span};
38
42
use smallvec::SmallVec;
39
43
@@ -474,6 +478,77 @@ fn subst_and_check_impossible_predicates<'tcx>(
474
478
result
475
479
}
476
480
481
+ /// Checks whether a trait's method is impossible to call on a given impl.
482
+ ///
483
+ /// This only considers predicates that reference the impl's generics, and not
484
+ /// those that reference the method's generics.
485
+ fn is_impossible_method<'tcx>(
486
+ tcx: TyCtxt<'tcx>,
487
+ (impl_def_id, trait_item_def_id): (DefId, DefId),
488
+ ) -> bool {
489
+ struct ReferencesOnlyParentGenerics<'tcx> {
490
+ tcx: TyCtxt<'tcx>,
491
+ generics: &'tcx ty::Generics,
492
+ trait_item_def_id: DefId,
493
+ }
494
+ impl<'tcx> ty::TypeVisitor<'tcx> for ReferencesOnlyParentGenerics<'tcx> {
495
+ type BreakTy = ();
496
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
497
+ // If this is a parameter from the trait item's own generics, then bail
498
+ if let ty::Param(param) = t.kind()
499
+ && let param_def_id = self.generics.type_param(param, self.tcx).def_id
500
+ && self.tcx.parent(param_def_id) == self.trait_item_def_id
501
+ {
502
+ return ControlFlow::BREAK;
503
+ }
504
+ t.super_visit_with(self)
505
+ }
506
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
507
+ if let ty::ReEarlyBound(param) = r.kind()
508
+ && let param_def_id = self.generics.region_param(¶m, self.tcx).def_id
509
+ && self.tcx.parent(param_def_id) == self.trait_item_def_id
510
+ {
511
+ return ControlFlow::BREAK;
512
+ }
513
+ r.super_visit_with(self)
514
+ }
515
+ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
516
+ if let ty::ConstKind::Param(param) = ct.kind()
517
+ && let param_def_id = self.generics.const_param(¶m, self.tcx).def_id
518
+ && self.tcx.parent(param_def_id) == self.trait_item_def_id
519
+ {
520
+ return ControlFlow::BREAK;
521
+ }
522
+ ct.super_visit_with(self)
523
+ }
524
+ }
525
+
526
+ let generics = tcx.generics_of(trait_item_def_id);
527
+ let predicates = tcx.predicates_of(trait_item_def_id);
528
+ let impl_trait_ref =
529
+ tcx.impl_trait_ref(impl_def_id).expect("expected impl to correspond to trait");
530
+ let param_env = tcx.param_env(impl_def_id);
531
+
532
+ let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id };
533
+ let predicates_for_trait = predicates.predicates.iter().filter_map(|(pred, span)| {
534
+ if pred.visit_with(&mut visitor).is_continue() {
535
+ Some(Obligation::new(
536
+ ObligationCause::dummy_with_span(*span),
537
+ param_env,
538
+ ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs),
539
+ ))
540
+ } else {
541
+ None
542
+ }
543
+ });
544
+
545
+ tcx.infer_ctxt().ignoring_regions().enter(|ref infcx| {
546
+ let mut fulfill_ctxt = <dyn TraitEngine<'_>>::new(tcx);
547
+ fulfill_ctxt.register_predicate_obligations(infcx, predicates_for_trait);
548
+ !fulfill_ctxt.select_all_or_error(infcx).is_empty()
549
+ })
550
+ }
551
+
477
552
#[derive(Clone, Debug)]
478
553
enum VtblSegment<'tcx> {
479
554
MetadataDSA,
@@ -854,6 +929,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
854
929
vtable_entries,
855
930
vtable_trait_upcasting_coercion_new_vptr_slot,
856
931
subst_and_check_impossible_predicates,
932
+ is_impossible_method,
857
933
try_unify_abstract_consts: |tcx, param_env_and| {
858
934
let (param_env, (a, b)) = param_env_and.into_parts();
859
935
const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env)
0 commit comments