| 
1 |  | -use crate::rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;  | 
2 | 1 | use rustc_hir as hir;  | 
3 | 2 | use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt};  | 
4 | 3 | use rustc_infer::traits;  | 
5 |  | -use rustc_middle::ty::ToPredicate;  | 
 | 4 | +use rustc_middle::ty::{self, ToPredicate};  | 
 | 5 | +use rustc_span::def_id::DefId;  | 
6 | 6 | use rustc_span::DUMMY_SP;  | 
 | 7 | +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;  | 
7 | 8 | 
 
  | 
8 |  | -use super::*;  | 
 | 9 | +use thin_vec::ThinVec;  | 
9 | 10 | 
 
  | 
10 |  | -pub(crate) struct BlanketImplFinder<'a, 'tcx> {  | 
11 |  | -    pub(crate) cx: &'a mut core::DocContext<'tcx>,  | 
12 |  | -}  | 
 | 11 | +use crate::clean;  | 
 | 12 | +use crate::clean::{  | 
 | 13 | +    clean_middle_assoc_item, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty_generics,  | 
 | 14 | +};  | 
 | 15 | +use crate::core::DocContext;  | 
 | 16 | + | 
 | 17 | +#[instrument(level = "debug", skip(cx))]  | 
 | 18 | +pub(crate) fn synthesize_blanket_impls(  | 
 | 19 | +    cx: &mut DocContext<'_>,  | 
 | 20 | +    item_def_id: DefId,  | 
 | 21 | +) -> Vec<clean::Item> {  | 
 | 22 | +    let tcx = cx.tcx;  | 
 | 23 | +    let ty = tcx.type_of(item_def_id);  | 
13 | 24 | 
 
  | 
14 |  | -impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {  | 
15 |  | -    pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> {  | 
16 |  | -        let cx = &mut self.cx;  | 
17 |  | -        let ty = cx.tcx.type_of(item_def_id);  | 
 | 25 | +    let mut blanket_impls = Vec::new();  | 
 | 26 | +    for trait_def_id in tcx.all_traits() {  | 
 | 27 | +        if !cx.cache.effective_visibilities.is_reachable(tcx, trait_def_id)  | 
 | 28 | +            || cx.generated_synthetics.get(&(ty.skip_binder(), trait_def_id)).is_some()  | 
 | 29 | +        {  | 
 | 30 | +            continue;  | 
 | 31 | +        }  | 
 | 32 | +        // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls  | 
 | 33 | +        let trait_impls = tcx.trait_impls_of(trait_def_id);  | 
 | 34 | +        'blanket_impls: for &impl_def_id in trait_impls.blanket_impls() {  | 
 | 35 | +            trace!("considering impl `{impl_def_id:?}` for trait `{trait_def_id:?}`");  | 
18 | 36 | 
 
  | 
19 |  | -        trace!("get_blanket_impls({ty:?})");  | 
20 |  | -        let mut impls = Vec::new();  | 
21 |  | -        for trait_def_id in cx.tcx.all_traits() {  | 
22 |  | -            if !cx.cache.effective_visibilities.is_reachable(cx.tcx, trait_def_id)  | 
23 |  | -                || cx.generated_synthetics.get(&(ty.skip_binder(), trait_def_id)).is_some()  | 
24 |  | -            {  | 
 | 37 | +            let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();  | 
 | 38 | +            if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {  | 
25 | 39 |                 continue;  | 
26 | 40 |             }  | 
27 |  | -            // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls  | 
28 |  | -            let trait_impls = cx.tcx.trait_impls_of(trait_def_id);  | 
29 |  | -            'blanket_impls: for &impl_def_id in trait_impls.blanket_impls() {  | 
30 |  | -                trace!(  | 
31 |  | -                    "get_blanket_impls: Considering impl for trait '{:?}' {:?}",  | 
32 |  | -                    trait_def_id,  | 
33 |  | -                    impl_def_id  | 
34 |  | -                );  | 
35 |  | -                let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap();  | 
36 |  | -                if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {  | 
37 |  | -                    continue;  | 
38 |  | -                }  | 
39 |  | -                let infcx = cx.tcx.infer_ctxt().build();  | 
40 |  | -                let args = infcx.fresh_args_for_item(DUMMY_SP, item_def_id);  | 
41 |  | -                let impl_ty = ty.instantiate(infcx.tcx, args);  | 
42 |  | -                let param_env = ty::ParamEnv::empty();  | 
 | 41 | +            let infcx = tcx.infer_ctxt().build();  | 
 | 42 | +            let args = infcx.fresh_args_for_item(DUMMY_SP, item_def_id);  | 
 | 43 | +            let impl_ty = ty.instantiate(tcx, args);  | 
 | 44 | +            let param_env = ty::ParamEnv::empty();  | 
43 | 45 | 
 
  | 
44 |  | -                let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);  | 
45 |  | -                let impl_trait_ref = trait_ref.instantiate(infcx.tcx, impl_args);  | 
 | 46 | +            let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);  | 
 | 47 | +            let impl_trait_ref = trait_ref.instantiate(tcx, impl_args);  | 
46 | 48 | 
 
  | 
47 |  | -                // Require the type the impl is implemented on to match  | 
48 |  | -                // our type, and ignore the impl if there was a mismatch.  | 
49 |  | -                let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq(  | 
50 |  | -                    DefineOpaqueTypes::Yes,  | 
51 |  | -                    impl_trait_ref.self_ty(),  | 
52 |  | -                    impl_ty,  | 
53 |  | -                ) else {  | 
54 |  | -                    continue;  | 
55 |  | -                };  | 
56 |  | -                let InferOk { value: (), obligations } = eq_result;  | 
57 |  | -                // FIXME(eddyb) ignoring `obligations` might cause false positives.  | 
58 |  | -                drop(obligations);  | 
 | 49 | +            // Require the type the impl is implemented on to match  | 
 | 50 | +            // our type, and ignore the impl if there was a mismatch.  | 
 | 51 | +            let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq(  | 
 | 52 | +                DefineOpaqueTypes::Yes,  | 
 | 53 | +                impl_trait_ref.self_ty(),  | 
 | 54 | +                impl_ty,  | 
 | 55 | +            ) else {  | 
 | 56 | +                continue;  | 
 | 57 | +            };  | 
 | 58 | +            let InferOk { value: (), obligations } = eq_result;  | 
 | 59 | +            // FIXME(eddyb) ignoring `obligations` might cause false positives.  | 
 | 60 | +            drop(obligations);  | 
59 | 61 | 
 
  | 
60 |  | -                trace!(  | 
61 |  | -                    "invoking predicate_may_hold: param_env={:?}, impl_trait_ref={:?}, impl_ty={:?}",  | 
 | 62 | +            let predicates = tcx  | 
 | 63 | +                .predicates_of(impl_def_id)  | 
 | 64 | +                .instantiate(tcx, impl_args)  | 
 | 65 | +                .predicates  | 
 | 66 | +                .into_iter()  | 
 | 67 | +                .chain(Some(ty::Binder::dummy(impl_trait_ref).to_predicate(tcx)));  | 
 | 68 | +            for predicate in predicates {  | 
 | 69 | +                let obligation = traits::Obligation::new(  | 
 | 70 | +                    tcx,  | 
 | 71 | +                    traits::ObligationCause::dummy(),  | 
62 | 72 |                     param_env,  | 
63 |  | -                    impl_trait_ref,  | 
64 |  | -                    impl_ty  | 
 | 73 | +                    predicate,  | 
65 | 74 |                 );  | 
66 |  | -                let predicates = cx  | 
67 |  | -                    .tcx  | 
68 |  | -                    .predicates_of(impl_def_id)  | 
69 |  | -                    .instantiate(cx.tcx, impl_args)  | 
70 |  | -                    .predicates  | 
71 |  | -                    .into_iter()  | 
72 |  | -                    .chain(Some(ty::Binder::dummy(impl_trait_ref).to_predicate(infcx.tcx)));  | 
73 |  | -                for predicate in predicates {  | 
74 |  | -                    debug!("testing predicate {predicate:?}");  | 
75 |  | -                    let obligation = traits::Obligation::new(  | 
76 |  | -                        infcx.tcx,  | 
77 |  | -                        traits::ObligationCause::dummy(),  | 
78 |  | -                        param_env,  | 
79 |  | -                        predicate,  | 
80 |  | -                    );  | 
81 |  | -                    match infcx.evaluate_obligation(&obligation) {  | 
82 |  | -                        Ok(eval_result) if eval_result.may_apply() => {}  | 
83 |  | -                        Err(traits::OverflowError::Canonical) => {}  | 
84 |  | -                        _ => continue 'blanket_impls,  | 
85 |  | -                    }  | 
 | 75 | +                match infcx.evaluate_obligation(&obligation) {  | 
 | 76 | +                    Ok(eval_result) if eval_result.may_apply() => {}  | 
 | 77 | +                    Err(traits::OverflowError::Canonical) => {}  | 
 | 78 | +                    _ => continue 'blanket_impls,  | 
86 | 79 |                 }  | 
87 |  | -                debug!(  | 
88 |  | -                    "get_blanket_impls: found applicable impl for trait_ref={:?}, ty={:?}",  | 
89 |  | -                    trait_ref, ty  | 
90 |  | -                );  | 
 | 80 | +            }  | 
 | 81 | +            debug!("found applicable impl for trait ref {trait_ref:?}");  | 
91 | 82 | 
 
  | 
92 |  | -                cx.generated_synthetics.insert((ty.skip_binder(), trait_def_id));  | 
 | 83 | +            cx.generated_synthetics.insert((ty.skip_binder(), trait_def_id));  | 
93 | 84 | 
 
  | 
94 |  | -                impls.push(Item {  | 
95 |  | -                    name: None,  | 
96 |  | -                    attrs: Default::default(),  | 
97 |  | -                    item_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },  | 
98 |  | -                    kind: Box::new(ImplItem(Box::new(Impl {  | 
99 |  | -                        unsafety: hir::Unsafety::Normal,  | 
100 |  | -                        generics: clean_ty_generics(  | 
101 |  | -                            cx,  | 
102 |  | -                            cx.tcx.generics_of(impl_def_id),  | 
103 |  | -                            cx.tcx.explicit_predicates_of(impl_def_id),  | 
104 |  | -                        ),  | 
105 |  | -                        // FIXME(eddyb) compute both `trait_` and `for_` from  | 
106 |  | -                        // the post-inference `trait_ref`, as it's more accurate.  | 
107 |  | -                        trait_: Some(clean_trait_ref_with_bindings(  | 
108 |  | -                            cx,  | 
109 |  | -                            ty::Binder::dummy(trait_ref.instantiate_identity()),  | 
110 |  | -                            ThinVec::new(),  | 
111 |  | -                        )),  | 
112 |  | -                        for_: clean_middle_ty(  | 
113 |  | -                            ty::Binder::dummy(ty.instantiate_identity()),  | 
114 |  | -                            cx,  | 
115 |  | -                            None,  | 
116 |  | -                            None,  | 
117 |  | -                        ),  | 
118 |  | -                        items: cx  | 
119 |  | -                            .tcx  | 
120 |  | -                            .associated_items(impl_def_id)  | 
121 |  | -                            .in_definition_order()  | 
122 |  | -                            .filter(|item| !item.is_impl_trait_in_trait())  | 
123 |  | -                            .map(|item| clean_middle_assoc_item(item, cx))  | 
124 |  | -                            .collect::<Vec<_>>(),  | 
125 |  | -                        polarity: ty::ImplPolarity::Positive,  | 
126 |  | -                        kind: ImplKind::Blanket(Box::new(clean_middle_ty(  | 
127 |  | -                            ty::Binder::dummy(trait_ref.instantiate_identity().self_ty()),  | 
128 |  | -                            cx,  | 
129 |  | -                            None,  | 
130 |  | -                            None,  | 
131 |  | -                        ))),  | 
132 |  | -                    }))),  | 
133 |  | -                    cfg: None,  | 
134 |  | -                    inline_stmt_id: None,  | 
135 |  | -                });  | 
136 |  | -            }  | 
 | 85 | +            blanket_impls.push(clean::Item {  | 
 | 86 | +                name: None,  | 
 | 87 | +                attrs: Default::default(),  | 
 | 88 | +                item_id: clean::ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },  | 
 | 89 | +                kind: Box::new(clean::ImplItem(Box::new(clean::Impl {  | 
 | 90 | +                    unsafety: hir::Unsafety::Normal,  | 
 | 91 | +                    generics: clean_ty_generics(  | 
 | 92 | +                        cx,  | 
 | 93 | +                        tcx.generics_of(impl_def_id),  | 
 | 94 | +                        tcx.explicit_predicates_of(impl_def_id),  | 
 | 95 | +                    ),  | 
 | 96 | +                    // FIXME(eddyb) compute both `trait_` and `for_` from  | 
 | 97 | +                    // the post-inference `trait_ref`, as it's more accurate.  | 
 | 98 | +                    trait_: Some(clean_trait_ref_with_bindings(  | 
 | 99 | +                        cx,  | 
 | 100 | +                        ty::Binder::dummy(trait_ref.instantiate_identity()),  | 
 | 101 | +                        ThinVec::new(),  | 
 | 102 | +                    )),  | 
 | 103 | +                    for_: clean_middle_ty(  | 
 | 104 | +                        ty::Binder::dummy(ty.instantiate_identity()),  | 
 | 105 | +                        cx,  | 
 | 106 | +                        None,  | 
 | 107 | +                        None,  | 
 | 108 | +                    ),  | 
 | 109 | +                    items: tcx  | 
 | 110 | +                        .associated_items(impl_def_id)  | 
 | 111 | +                        .in_definition_order()  | 
 | 112 | +                        .filter(|item| !item.is_impl_trait_in_trait())  | 
 | 113 | +                        .map(|item| clean_middle_assoc_item(item, cx))  | 
 | 114 | +                        .collect(),  | 
 | 115 | +                    polarity: ty::ImplPolarity::Positive,  | 
 | 116 | +                    kind: clean::ImplKind::Blanket(Box::new(clean_middle_ty(  | 
 | 117 | +                        ty::Binder::dummy(trait_ref.instantiate_identity().self_ty()),  | 
 | 118 | +                        cx,  | 
 | 119 | +                        None,  | 
 | 120 | +                        None,  | 
 | 121 | +                    ))),  | 
 | 122 | +                }))),  | 
 | 123 | +                cfg: None,  | 
 | 124 | +                inline_stmt_id: None,  | 
 | 125 | +            });  | 
137 | 126 |         }  | 
138 |  | - | 
139 |  | -        impls  | 
140 | 127 |     }  | 
 | 128 | + | 
 | 129 | +    blanket_impls  | 
141 | 130 | }  | 
0 commit comments