@@ -53,12 +53,15 @@ use rustc_data_structures::captures::Captures;
53
53
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
54
54
use rustc_hir::def_id::{DefId, DefIdSet};
55
55
use rustc_hir::Mutability;
56
+ use rustc_infer::infer::TyCtxtInferExt;
57
+ use rustc_infer::traits::{Obligation, ObligationCause};
56
58
use rustc_middle::middle::stability;
57
- use rustc_middle:: ty:: TyCtxt ;
59
+ use rustc_middle::ty::{ParamEnv, TyCtxt} ;
58
60
use rustc_span::{
59
61
symbol::{sym, Symbol},
60
62
BytePos, FileName, RealFileName,
61
63
};
64
+ use rustc_trait_selection::traits::ObligationCtxt;
62
65
use serde::ser::{SerializeMap, SerializeSeq};
63
66
use serde::{Serialize, Serializer};
64
67
@@ -1112,28 +1115,76 @@ fn render_assoc_items<'a, 'cx: 'a>(
1112
1115
containing_item: &'a clean::Item,
1113
1116
it: DefId,
1114
1117
what: AssocItemRender<'a>,
1118
+ aliased_type: Option<DefId>,
1115
1119
) -> impl fmt::Display + 'a + Captures<'cx> {
1116
1120
let mut derefs = DefIdSet::default();
1117
1121
derefs.insert(it);
1118
1122
display_fn(move |f| {
1119
- render_assoc_items_inner ( f, cx, containing_item, it, what, & mut derefs) ;
1123
+ render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs, aliased_type );
1120
1124
Ok(())
1121
1125
})
1122
1126
}
1123
1127
1128
+ /// Check whether `impl_def_id` may apply to *some instantiation* of `item_def_id`.
1129
+ fn is_valid_impl_for(tcx: TyCtxt<'_>, item_def_id: DefId, impl_def_id: DefId) -> bool {
1130
+ let infcx = tcx.infer_ctxt().intercrate(true).build();
1131
+ let ocx = ObligationCtxt::new(&infcx);
1132
+ let param_env = ParamEnv::empty();
1133
+
1134
+ let alias_substs = infcx.fresh_substs_for_item(rustc_span::DUMMY_SP, item_def_id);
1135
+ let alias_ty = tcx.type_of(item_def_id).subst(tcx, alias_substs);
1136
+ let alias_bounds = tcx.predicates_of(item_def_id).instantiate(tcx, alias_substs);
1137
+
1138
+ let impl_substs = infcx.fresh_substs_for_item(rustc_span::DUMMY_SP, impl_def_id);
1139
+ let impl_self_ty = tcx.type_of(impl_def_id).subst(tcx, impl_substs);
1140
+ let impl_bounds = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs);
1141
+
1142
+ if ocx.eq(&ObligationCause::dummy(), param_env, impl_self_ty, alias_ty).is_err() {
1143
+ return false;
1144
+ }
1145
+ ocx.register_obligations(
1146
+ alias_bounds
1147
+ .iter()
1148
+ .chain(impl_bounds)
1149
+ .map(|(p, _)| Obligation::new(tcx, ObligationCause::dummy(), param_env, p)),
1150
+ );
1151
+
1152
+ let errors = ocx.select_where_possible();
1153
+ errors.is_empty()
1154
+ }
1155
+
1156
+ // If `aliased_type` is `Some`, it means `it` is a type alias and `aliased_type` is the "actual"
1157
+ // type aliased behind `it`. It is used to check whether or not the implementation of the aliased
1158
+ // type can be displayed on the alias doc page.
1124
1159
fn render_assoc_items_inner(
1125
1160
mut w: &mut dyn fmt::Write,
1126
1161
cx: &mut Context<'_>,
1127
1162
containing_item: &clean::Item,
1128
1163
it: DefId,
1129
1164
what: AssocItemRender<'_>,
1130
1165
derefs: &mut DefIdSet,
1166
+ aliased_type: Option<DefId>,
1131
1167
) {
1132
1168
info!("Documenting associated items of {:?}", containing_item.name);
1133
1169
let shared = Rc::clone(&cx.shared);
1134
1170
let cache = &shared.cache;
1135
- let Some ( v) = cache. impls . get ( & it) else { return } ;
1136
- let ( non_trait, traits) : ( Vec < _ > , _ ) = v. iter ( ) . partition ( |i| i. inner_impl ( ) . trait_ . is_none ( ) ) ;
1171
+ let empty = Vec::new();
1172
+ let v = match cache.impls.get(&it) {
1173
+ Some(v) => v,
1174
+ None => &empty,
1175
+ };
1176
+ let v2 = match aliased_type {
1177
+ Some(aliased_type) => cache.impls.get(&aliased_type).unwrap_or(&empty),
1178
+ None => &empty,
1179
+ };
1180
+ if v.is_empty() && v2.is_empty() {
1181
+ return;
1182
+ }
1183
+ let mut saw_impls = FxHashSet::default();
1184
+ let (non_trait, traits): (Vec<_>, _) =
1185
+ v.iter().chain(v2).partition(|i| i.inner_impl().trait_.is_none());
1186
+ let tcx = cx.tcx();
1187
+ let is_alias = aliased_type.is_some();
1137
1188
if !non_trait.is_empty() {
1138
1189
let mut tmp_buf = Buffer::html();
1139
1190
let (render_mode, id, class_html) = match what {
@@ -1165,6 +1216,12 @@ fn render_assoc_items_inner(
1165
1216
};
1166
1217
let mut impls_buf = Buffer::html();
1167
1218
for i in &non_trait {
1219
+ if !saw_impls.insert(i.def_id()) {
1220
+ continue;
1221
+ }
1222
+ if is_alias && !is_valid_impl_for(tcx, it, i.def_id()) {
1223
+ continue;
1224
+ }
1168
1225
render_impl(
1169
1226
&mut impls_buf,
1170
1227
cx,
@@ -1193,9 +1250,14 @@ fn render_assoc_items_inner(
1193
1250
if !traits.is_empty() {
1194
1251
let deref_impl =
1195
1252
traits.iter().find(|t| t.trait_did() == cx.tcx().lang_items().deref_trait());
1196
- if let Some ( impl_) = deref_impl {
1253
+ if let Some(impl_) = deref_impl &&
1254
+ (!is_alias || is_valid_impl_for(tcx, it, impl_.def_id()))
1255
+ {
1197
1256
let has_deref_mut =
1198
- traits. iter ( ) . any ( |t| t. trait_did ( ) == cx. tcx ( ) . lang_items ( ) . deref_mut_trait ( ) ) ;
1257
+ traits.iter().any(|t| {
1258
+ t.trait_did() == cx.tcx().lang_items().deref_mut_trait() &&
1259
+ (!is_alias || is_valid_impl_for(tcx, it, t.def_id()))
1260
+ });
1199
1261
render_deref_methods(&mut w, cx, impl_, containing_item, has_deref_mut, derefs);
1200
1262
}
1201
1263
@@ -1205,10 +1267,14 @@ fn render_assoc_items_inner(
1205
1267
return;
1206
1268
}
1207
1269
1208
- let ( synthetic, concrete) : ( Vec < & Impl > , Vec < & Impl > ) =
1209
- traits. into_iter ( ) . partition ( |t| t. inner_impl ( ) . kind . is_auto ( ) ) ;
1210
- let ( blanket_impl, concrete) : ( Vec < & Impl > , _ ) =
1211
- concrete. into_iter ( ) . partition ( |t| t. inner_impl ( ) . kind . is_blanket ( ) ) ;
1270
+ let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = traits
1271
+ .into_iter()
1272
+ .filter(|t| saw_impls.insert(t.def_id()))
1273
+ .partition(|t| t.inner_impl().kind.is_auto());
1274
+ let (blanket_impl, concrete): (Vec<&Impl>, _) = concrete
1275
+ .into_iter()
1276
+ .filter(|t| !is_alias || is_valid_impl_for(tcx, it, t.def_id()))
1277
+ .partition(|t| t.inner_impl().kind.is_blanket());
1212
1278
1213
1279
render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl);
1214
1280
}
@@ -1247,10 +1313,10 @@ fn render_deref_methods(
1247
1313
return;
1248
1314
}
1249
1315
}
1250
- render_assoc_items_inner ( & mut w, cx, container_item, did, what, derefs) ;
1316
+ render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs, None );
1251
1317
} else if let Some(prim) = target.primitive_type() {
1252
1318
if let Some(&did) = cache.primitive_locations.get(&prim) {
1253
- render_assoc_items_inner ( & mut w, cx, container_item, did, what, derefs) ;
1319
+ render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs, None );
1254
1320
}
1255
1321
}
1256
1322
}
0 commit comments