Skip to content

Commit 0e2f486

Browse files
committed
Auto merge of #148379 - obi1kenobi:pg/implied-bounds, r=<try>
Add implied bounds to generic types, impl Trait, and assoc types.
2 parents 0462e8f + 658536c commit 0e2f486

43 files changed

Lines changed: 2624 additions & 200 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/librustdoc/clean/mod.rs

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use rustc_hir as hir;
4242
use rustc_hir::attrs::{AttributeKind, DocAttribute, DocInline};
4343
use rustc_hir::def::{CtorKind, DefKind, MacroKinds, Res};
4444
use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId};
45-
use rustc_hir::{LangItem, PredicateOrigin, find_attr};
45+
use rustc_hir::{LangItem, OpaqueTyOrigin, PredicateOrigin, find_attr};
4646
use rustc_hir_analysis::{lower_const_arg_for_rustdoc, lower_ty};
4747
use rustc_middle::metadata::Reexport;
4848
use rustc_middle::middle::resolve_bound_vars as rbv;
@@ -458,7 +458,7 @@ fn clean_type_outlives_predicate<'tcx>(
458458
}
459459
}
460460

461-
fn clean_middle_term<'tcx>(
461+
pub(crate) fn clean_middle_term<'tcx>(
462462
term: ty::Binder<'tcx, ty::Term<'tcx>>,
463463
cx: &mut DocContext<'tcx>,
464464
) -> Term {
@@ -526,7 +526,7 @@ fn should_fully_qualify_path(self_def_id: Option<DefId>, trait_: &Path, self_typ
526526
.map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_)
527527
}
528528

529-
fn projection_to_path_segment<'tcx>(
529+
pub(crate) fn projection_to_path_segment<'tcx>(
530530
proj: ty::Binder<'tcx, ty::AliasTerm<'tcx>>,
531531
cx: &mut DocContext<'tcx>,
532532
) -> PathSegment {
@@ -698,8 +698,13 @@ pub(crate) fn clean_generics<'tcx>(
698698
let param = clean_generic_param(cx, Some(gens), param);
699699
match param.kind {
700700
GenericParamDefKind::Lifetime { .. } => unreachable!(),
701-
GenericParamDefKind::Type { ref bounds, .. } => {
702-
cx.impl_trait_bounds.insert(param.def_id.into(), bounds.to_vec());
701+
GenericParamDefKind::Type { ref bounds, ref synthetic, .. } => {
702+
debug_assert!(*synthetic, "non-synthetic generic for impl trait: {param:?}");
703+
let param_def_id = param.def_id;
704+
cx.impl_trait_bounds.insert(
705+
param_def_id.into(),
706+
(bounds.to_vec(), ImplTraitOrigin::Param { def_id: param_def_id }),
707+
);
703708
}
704709
GenericParamDefKind::Const { .. } => unreachable!(),
705710
}
@@ -819,7 +824,7 @@ fn clean_ty_generics_inner<'tcx>(
819824
) -> Generics {
820825
// Don't populate `cx.impl_trait_bounds` before cleaning where clauses,
821826
// since `clean_predicate` would consume them.
822-
let mut impl_trait = BTreeMap::<u32, Vec<GenericBound>>::default();
827+
let mut impl_trait = BTreeMap::<u32, (DefId, Vec<GenericBound>)>::default();
823828

824829
let params: ThinVec<_> = gens
825830
.own_params
@@ -832,7 +837,7 @@ fn clean_ty_generics_inner<'tcx>(
832837
return false;
833838
}
834839
if synthetic {
835-
impl_trait.insert(param.index, vec![]);
840+
impl_trait.insert(param.index, (param.def_id, vec![]));
836841
return false;
837842
}
838843
true
@@ -873,7 +878,7 @@ fn clean_ty_generics_inner<'tcx>(
873878
};
874879

875880
if let Some(param_idx) = param_idx
876-
&& let Some(bounds) = impl_trait.get_mut(&param_idx)
881+
&& let Some((_, bounds)) = impl_trait.get_mut(&param_idx)
877882
{
878883
let pred = clean_predicate(*pred, cx)?;
879884

@@ -895,7 +900,7 @@ fn clean_ty_generics_inner<'tcx>(
895900
})
896901
.collect::<Vec<_>>();
897902

898-
for (idx, mut bounds) in impl_trait {
903+
for (idx, (param_def_id, mut bounds)) in impl_trait {
899904
let mut has_sized = false;
900905
bounds.retain(|b| {
901906
if b.is_sized_bound(cx) {
@@ -929,7 +934,8 @@ fn clean_ty_generics_inner<'tcx>(
929934
}
930935
}
931936

932-
cx.impl_trait_bounds.insert(idx.into(), bounds);
937+
cx.impl_trait_bounds
938+
.insert(idx.into(), (bounds, ImplTraitOrigin::Param { def_id: param_def_id }));
933939
}
934940

935941
// Now that `cx.impl_trait_bounds` is populated, we can process
@@ -1157,7 +1163,7 @@ fn clean_poly_fn_sig<'tcx>(
11571163
// function isn't async without needing to execute the query `asyncness` at
11581164
// all which gives us a noticeable performance boost.
11591165
if let Some(did) = did
1160-
&& let Type::ImplTrait(_) = output
1166+
&& let Type::ImplTrait { .. } = output
11611167
&& cx.tcx.asyncness(did).is_async()
11621168
{
11631169
output = output.sugared_async_return_type();
@@ -1648,8 +1654,8 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
16481654
if let Some(new_ty) = cx.args.get(&did).and_then(|p| p.as_ty()).cloned() {
16491655
return new_ty;
16501656
}
1651-
if let Some(bounds) = cx.impl_trait_bounds.remove(&did.into()) {
1652-
return ImplTrait(bounds);
1657+
if let Some((bounds, origin)) = cx.impl_trait_bounds.remove(&did.into()) {
1658+
return ImplTrait { bounds, origin };
16531659
}
16541660
}
16551661

@@ -1838,7 +1844,15 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
18381844
}
18391845
TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
18401846
TyKind::OpaqueDef(ty) => {
1841-
ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
1847+
let bounds =
1848+
ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect::<Vec<_>>();
1849+
ImplTrait {
1850+
bounds,
1851+
origin: ImplTraitOrigin::Opaque {
1852+
def_id: ty.def_id.to_def_id(),
1853+
needs_sized_check: opaque_needs_sized_check(&ty.origin),
1854+
},
1855+
}
18421856
}
18431857
TyKind::Path(_) => clean_qpath(ty, cx),
18441858
TyKind::TraitObject(bounds, lifetime) => {
@@ -2226,8 +2240,8 @@ pub(crate) fn clean_middle_ty<'tcx>(
22262240
}
22272241

22282242
ty::Param(ref p) => {
2229-
if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
2230-
ImplTrait(bounds)
2243+
if let Some((bounds, origin)) = cx.impl_trait_bounds.remove(&p.index.into()) {
2244+
ImplTrait { bounds, origin }
22312245
} else if p.name == kw::SelfUpper {
22322246
SelfTy
22332247
} else {
@@ -2363,7 +2377,24 @@ fn clean_middle_opaque_bounds<'tcx>(
23632377
));
23642378
}
23652379

2366-
ImplTrait(bounds)
2380+
ImplTrait {
2381+
bounds,
2382+
origin: ImplTraitOrigin::Opaque {
2383+
def_id: impl_trait_def_id,
2384+
needs_sized_check: if cx.tcx.opt_rpitit_info(impl_trait_def_id).is_some() {
2385+
// RPITIT uses can imply `Sized` unless used behind indirection,
2386+
// so a precise check is necessary.
2387+
true
2388+
} else if impl_trait_def_id.is_local() {
2389+
opaque_needs_sized_check(&cx.tcx.opaque_ty_origin(impl_trait_def_id))
2390+
} else {
2391+
// Extern opaques don't carry origin metadata.
2392+
// Skip the use-site check to avoid an ICE.
2393+
// FIXME: Get metadata on sizedness for extern opaques, then make this precise.
2394+
false
2395+
},
2396+
},
2397+
}
23672398
}
23682399

23692400
pub(crate) fn clean_field<'tcx>(field: &hir::FieldDef<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
@@ -2626,6 +2657,17 @@ fn clean_unsafe_binder_ty<'tcx>(
26262657
UnsafeBinderTy { generic_params, ty }
26272658
}
26282659

2660+
fn opaque_needs_sized_check<D>(origin: &OpaqueTyOrigin<D>) -> bool {
2661+
match origin {
2662+
// Return-position opaques need a sizedness check at their use-site,
2663+
// even if they have a `?Sized` bound.
2664+
OpaqueTyOrigin::FnReturn { .. } | OpaqueTyOrigin::AsyncFn { .. } => true,
2665+
// TAITs don't need a use-site sizedness check.
2666+
// `?Sized` in their definition always opts them out of being sized.
2667+
OpaqueTyOrigin::TyAlias { .. } => false,
2668+
}
2669+
}
2670+
26292671
pub(crate) fn reexport_chain(
26302672
tcx: TyCtxt<'_>,
26312673
import_def_id: LocalDefId,
@@ -3177,7 +3219,7 @@ fn clean_assoc_item_constraint<'tcx>(
31773219
}
31783220
}
31793221

3180-
fn clean_bound_vars<'tcx>(
3222+
pub(crate) fn clean_bound_vars<'tcx>(
31813223
bound_vars: &ty::List<ty::BoundVariableKind>,
31823224
cx: &mut DocContext<'tcx>,
31833225
) -> Vec<GenericParamDef> {

src/librustdoc/clean/types.rs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,31 @@ pub(crate) struct PolyTrait {
12921292
pub(crate) generic_params: Vec<GenericParamDef>,
12931293
}
12941294

1295+
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
1296+
pub(crate) enum ImplTraitOrigin {
1297+
/// Synthetic type parameter for `impl Trait` in argument position.
1298+
Param { def_id: DefId },
1299+
1300+
/// Opaque type backing `impl Trait`, such as in RPIT or TAIT.
1301+
///
1302+
/// `impl Trait` uses are `Sized` by default, but they can opt out via a `?Sized` bound.
1303+
/// `needs_sized_check` is `true` when the opaque is in a category that requires a
1304+
/// point-of-use sizedness check to determine if an implied `Sized` bound is added.
1305+
///
1306+
/// `needs_sized_check = true` occurs in cases like:
1307+
/// - RPIT: `fn f() -> impl Debug { 0u8 }`
1308+
/// - RPITIT: `trait T { fn f(&self) -> impl Debug; }`
1309+
///
1310+
/// `needs_sized_check = false` occurs in cases like:
1311+
/// - TAIT/ATPIT: `type Alias = impl Debug + ?Sized;`
1312+
///
1313+
/// A `true` value for `needs_sized_check` does not guarantee the opaque is `Sized`.
1314+
/// For example, `fn f() -> &(impl Debug + ?Sized) { "hi" }` has a return-position opaque
1315+
/// which makes `needs_sized_check = true`, but as the opaque is behind a reference,
1316+
/// it does not end up getting a `Sized` bound.
1317+
Opaque { def_id: DefId, needs_sized_check: bool },
1318+
}
1319+
12951320
/// Rustdoc's representation of types, mostly based on the [`hir::Ty`].
12961321
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
12971322
pub(crate) enum Type {
@@ -1337,7 +1362,25 @@ pub(crate) enum Type {
13371362
Infer,
13381363

13391364
/// An `impl Trait`: `impl TraitA + TraitB + ...`
1340-
ImplTrait(Vec<GenericBound>),
1365+
ImplTrait {
1366+
/// The bounds that are syntactically present:
1367+
/// ```rust
1368+
/// # trait TraitA {}
1369+
/// # trait TraitB {}
1370+
/// # struct Both;
1371+
/// # impl TraitA for Both {}
1372+
/// # impl TraitB for Both {}
1373+
/// fn example() -> impl TraitA + TraitB {
1374+
/// // ^^^^^^ ^^^^^^
1375+
/// // ...
1376+
/// # Both
1377+
/// }
1378+
/// ```
1379+
bounds: Vec<GenericBound>,
1380+
/// Whether this `impl Trait` is syntactic sugar for an anonymous generic parameter,
1381+
/// or represents an opaque type.
1382+
origin: ImplTraitOrigin,
1383+
},
13411384

13421385
UnsafeBinder(Box<UnsafeBinderTy>),
13431386
}
@@ -1465,8 +1508,8 @@ impl Type {
14651508
/// This function will panic if the return type does not match the expected sugaring for async
14661509
/// functions.
14671510
pub(crate) fn sugared_async_return_type(self) -> Type {
1468-
if let Type::ImplTrait(mut v) = self
1469-
&& let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = v.pop()
1511+
if let Type::ImplTrait { mut bounds, .. } = self
1512+
&& let Some(GenericBound::TraitBound(PolyTrait { mut trait_, .. }, _)) = bounds.pop()
14701513
&& let Some(segment) = trait_.segments.pop()
14711514
&& let GenericArgs::AngleBracketed { mut constraints, .. } = segment.args
14721515
&& let Some(constraint) = constraints.pop()
@@ -1536,7 +1579,7 @@ impl Type {
15361579
Type::Pat(..) => PrimitiveType::Pat,
15371580
RawPointer(..) => PrimitiveType::RawPointer,
15381581
QPath(box QPathData { self_type, .. }) => return self_type.def_id(cache),
1539-
Generic(_) | SelfTy | Infer | ImplTrait(_) | UnsafeBinder(_) => return None,
1582+
Generic(_) | SelfTy | Infer | ImplTrait { .. } | UnsafeBinder(_) => return None,
15401583
};
15411584
Primitive(t).def_id(cache)
15421585
}
@@ -2392,14 +2435,14 @@ mod size_asserts {
23922435
// tidy-alphabetical-start
23932436
static_assert_size!(Crate, 16); // frequently moved by-value
23942437
static_assert_size!(DocFragment, 48);
2395-
static_assert_size!(GenericArg, 32);
2438+
static_assert_size!(GenericArg, 40);
23962439
static_assert_size!(GenericArgs, 24);
23972440
static_assert_size!(GenericParamDef, 40);
23982441
static_assert_size!(Generics, 16);
23992442
static_assert_size!(Item, 8);
24002443
static_assert_size!(ItemInner, 144);
24012444
static_assert_size!(ItemKind, 48);
24022445
static_assert_size!(PathSegment, 32);
2403-
static_assert_size!(Type, 32);
2446+
static_assert_size!(Type, 40);
24042447
// tidy-alphabetical-end
24052448
}

src/librustdoc/core.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,10 @@ pub(crate) struct DocContext<'tcx> {
5454
// therefore wouldn't use the corresp. generic arg anyway. Add support for them.
5555
pub(crate) args: DefIdMap<clean::GenericArg>,
5656
pub(crate) current_type_aliases: DefIdMap<usize>,
57-
/// Table synthetic type parameter for `impl Trait` in argument position -> bounds
58-
pub(crate) impl_trait_bounds: FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>,
57+
/// Table of synthetic type parameter
58+
/// for `impl Trait` in argument position -> (bounds, trait origin)
59+
pub(crate) impl_trait_bounds:
60+
FxHashMap<ImplTraitParam, (Vec<clean::GenericBound>, clean::ImplTraitOrigin)>,
5961
/// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
6062
// FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
6163
pub(crate) generated_synthetics: FxHashSet<(Ty<'tcx>, DefId)>,

src/librustdoc/html/format.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,15 +1015,15 @@ fn fmt_type(
10151015
{
10161016
true
10171017
}
1018-
clean::ImplTrait(ref bounds) if bounds.len() > 1 => true,
1018+
clean::ImplTrait { ref bounds, .. } if bounds.len() > 1 => true,
10191019
_ => false,
10201020
};
10211021
Wrapped::with_parens()
10221022
.when(needs_parens)
10231023
.wrap_fn(|f| fmt_type(ty, f, use_absolute, cx))
10241024
.fmt(f)
10251025
}
1026-
clean::ImplTrait(bounds) => {
1026+
clean::ImplTrait { bounds, .. } => {
10271027
f.write_str("impl ")?;
10281028
print_generic_bounds(bounds, cx).fmt(f)
10291029
}

src/librustdoc/html/render/search_index.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2043,7 +2043,7 @@ fn get_index_type_id(
20432043
clean::Type::Pat(..)
20442044
| clean::Generic(_)
20452045
| clean::SelfTy
2046-
| clean::ImplTrait(_)
2046+
| clean::ImplTrait { .. }
20472047
| clean::Infer
20482048
| clean::UnsafeBinder(_) => None,
20492049
}
@@ -2141,7 +2141,7 @@ fn simplify_fn_type<'a, 'tcx>(
21412141
RenderType { id: Some(RenderTypeId::Index(idx)), generics: None, bindings: None }
21422142
})
21432143
}
2144-
Type::ImplTrait(ref bounds) => {
2144+
Type::ImplTrait { ref bounds, .. } => {
21452145
let type_bounds = bounds
21462146
.iter()
21472147
.filter_map(|bound| bound.get_trait_path())

0 commit comments

Comments
 (0)