Skip to content

Commit 520b5fa

Browse files
Rework hir Bounds collection
1 parent 270c94e commit 520b5fa

File tree

5 files changed

+127
-107
lines changed

5 files changed

+127
-107
lines changed

compiler/rustc_hir_analysis/src/astconv/mod.rs

+65-28
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
682682
ty::Binder::bind_with_vars(tcx.mk_trait_ref(trait_def_id, substs), bound_vars);
683683

684684
debug!(?poly_trait_ref, ?assoc_bindings);
685-
bounds.trait_bounds.push((poly_trait_ref, span, constness));
685+
bounds.push_trait_bound(tcx, poly_trait_ref, span, constness);
686686

687687
let mut dup_bindings = FxHashMap::default();
688688
for binding in &assoc_bindings {
@@ -853,18 +853,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
853853
}
854854

855855
/// Sets `implicitly_sized` to true on `Bounds` if necessary
856-
pub(crate) fn add_implicitly_sized<'hir>(
856+
pub(crate) fn add_implicitly_sized(
857857
&self,
858-
bounds: &mut Bounds<'hir>,
859-
ast_bounds: &'hir [hir::GenericBound<'hir>],
860-
self_ty_where_predicates: Option<(LocalDefId, &'hir [hir::WherePredicate<'hir>])>,
858+
bounds: &mut Bounds<'tcx>,
859+
self_ty: Ty<'tcx>,
860+
ast_bounds: &'tcx [hir::GenericBound<'tcx>],
861+
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
861862
span: Span,
862863
) {
863864
let tcx = self.tcx();
864865

865866
// Try to find an unbound in bounds.
866867
let mut unbound = None;
867-
let mut search_bounds = |ast_bounds: &'hir [hir::GenericBound<'hir>]| {
868+
let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
868869
for ab in ast_bounds {
869870
if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
870871
if unbound.is_none() {
@@ -912,7 +913,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
912913
// No lang item for `Sized`, so we can't add it as a bound.
913914
return;
914915
}
915-
bounds.implicitly_sized = Some(span);
916+
bounds.push_sized(tcx, self_ty, span);
916917
}
917918

918919
/// This helper takes a *converted* parameter type (`param_ty`)
@@ -963,10 +964,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
963964
}
964965
hir::GenericBound::Outlives(lifetime) => {
965966
let region = self.ast_region_to_region(lifetime, None);
966-
bounds.region_bounds.push((
967-
ty::Binder::bind_with_vars(region, bound_vars),
967+
bounds.push_region_bound(
968+
self.tcx(),
969+
ty::Binder::bind_with_vars(
970+
ty::OutlivesPredicate(param_ty, region),
971+
bound_vars,
972+
),
968973
lifetime.ident.span,
969-
));
974+
);
970975
}
971976
}
972977
}
@@ -1225,13 +1230,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
12251230
};
12261231
}
12271232
}
1228-
bounds.projection_bounds.push((
1229-
projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
1230-
projection_ty,
1231-
term: term,
1232-
}),
1233+
bounds.push_projection_bound(
1234+
tcx,
1235+
projection_ty
1236+
.map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
12331237
binding.span,
1234-
));
1238+
);
12351239
}
12361240
ConvertedBindingKind::Constraint(ast_bounds) => {
12371241
// "Desugar" a constraint like `T: Iterator<Item: Debug>` to
@@ -1260,7 +1264,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
12601264
fn conv_object_ty_poly_trait_ref(
12611265
&self,
12621266
span: Span,
1263-
trait_bounds: &[hir::PolyTraitRef<'_>],
1267+
hir_trait_bounds: &[hir::PolyTraitRef<'_>],
12641268
lifetime: &hir::Lifetime,
12651269
borrowed: bool,
12661270
representation: DynKind,
@@ -1270,7 +1274,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
12701274
let mut bounds = Bounds::default();
12711275
let mut potential_assoc_types = Vec::new();
12721276
let dummy_self = self.tcx().types.trait_object_dummy_self;
1273-
for trait_bound in trait_bounds.iter().rev() {
1277+
for trait_bound in hir_trait_bounds.iter().rev() {
12741278
if let GenericArgCountResult {
12751279
correct:
12761280
Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }),
@@ -1287,10 +1291,45 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
12871291
}
12881292
}
12891293

1294+
let mut trait_bounds = vec![];
1295+
let mut projection_bounds = vec![];
1296+
for (pred, span) in bounds.predicates() {
1297+
let bound_pred = pred.kind();
1298+
match bound_pred.skip_binder() {
1299+
ty::PredicateKind::Clause(clause) => match clause {
1300+
ty::Clause::Trait(trait_pred) => {
1301+
assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive);
1302+
trait_bounds.push((
1303+
bound_pred.rebind(trait_pred.trait_ref),
1304+
span,
1305+
trait_pred.constness,
1306+
));
1307+
}
1308+
ty::Clause::Projection(proj) => {
1309+
projection_bounds.push((bound_pred.rebind(proj), span));
1310+
}
1311+
ty::Clause::TypeOutlives(_) => {
1312+
// Do nothing, we deal with regions separately
1313+
}
1314+
ty::Clause::RegionOutlives(_) => bug!(),
1315+
},
1316+
ty::PredicateKind::WellFormed(_)
1317+
| ty::PredicateKind::ObjectSafe(_)
1318+
| ty::PredicateKind::ClosureKind(_, _, _)
1319+
| ty::PredicateKind::Subtype(_)
1320+
| ty::PredicateKind::Coerce(_)
1321+
| ty::PredicateKind::ConstEvaluatable(_)
1322+
| ty::PredicateKind::ConstEquate(_, _)
1323+
| ty::PredicateKind::TypeWellFormedFromEnv(_)
1324+
| ty::PredicateKind::Ambiguous => bug!(),
1325+
}
1326+
}
1327+
12901328
// Expand trait aliases recursively and check that only one regular (non-auto) trait
12911329
// is used and no 'maybe' bounds are used.
12921330
let expanded_traits =
1293-
traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().map(|&(a, b, _)| (a, b)));
1331+
traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b, _)| (a, b)));
1332+
12941333
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
12951334
.filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self)
12961335
.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
@@ -1327,8 +1366,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
13271366
}
13281367

13291368
if regular_traits.is_empty() && auto_traits.is_empty() {
1330-
let trait_alias_span = bounds
1331-
.trait_bounds
1369+
let trait_alias_span = trait_bounds
13321370
.iter()
13331371
.map(|&(trait_ref, _, _)| trait_ref.def_id())
13341372
.find(|&trait_ref| tcx.is_trait_alias(trait_ref))
@@ -1359,8 +1397,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
13591397
// Use a `BTreeSet` to keep output in a more consistent order.
13601398
let mut associated_types: FxHashMap<Span, BTreeSet<DefId>> = FxHashMap::default();
13611399

1362-
let regular_traits_refs_spans = bounds
1363-
.trait_bounds
1400+
let regular_traits_refs_spans = trait_bounds
13641401
.into_iter()
13651402
.filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
13661403

@@ -1414,15 +1451,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
14141451
// the discussion in #56288 for alternatives.
14151452
if !references_self {
14161453
// Include projections defined on supertraits.
1417-
bounds.projection_bounds.push((pred, span));
1454+
projection_bounds.push((pred, span));
14181455
}
14191456
}
14201457
_ => (),
14211458
}
14221459
}
14231460
}
14241461

1425-
for (projection_bound, _) in &bounds.projection_bounds {
1462+
for (projection_bound, _) in &projection_bounds {
14261463
for def_ids in associated_types.values_mut() {
14271464
def_ids.remove(&projection_bound.projection_def_id());
14281465
}
@@ -1431,7 +1468,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
14311468
self.complain_about_missing_associated_types(
14321469
associated_types,
14331470
potential_assoc_types,
1434-
trait_bounds,
1471+
hir_trait_bounds,
14351472
);
14361473

14371474
// De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
@@ -1473,7 +1510,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
14731510
let substs = tcx.intern_substs(&substs[..]);
14741511

14751512
let span = i.bottom().1;
1476-
let empty_generic_args = trait_bounds.iter().any(|hir_bound| {
1513+
let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
14771514
hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
14781515
&& hir_bound.span.contains(span)
14791516
});
@@ -1505,7 +1542,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
15051542
})
15061543
});
15071544

1508-
let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
1545+
let existential_projections = projection_bounds.iter().map(|(bound, _)| {
15091546
bound.map_bound(|mut b| {
15101547
assert_eq!(b.projection_ty.self_ty(), dummy_self);
15111548

+37-56
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Bounds are restrictions applied to some types after they've been converted into the
22
//! `ty` form from the HIR.
33
4+
use rustc_hir::LangItem;
45
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
56
use rustc_span::Span;
67

@@ -15,73 +16,53 @@ use rustc_span::Span;
1516
/// ^^^^^^^^^ bounding the type parameter `T`
1617
///
1718
/// impl dyn Bar + Baz
18-
/// ^^^^^^^^^ bounding the forgotten dynamic type
19+
/// ^^^^^^^^^ bounding the type-erased dynamic type
1920
/// ```
2021
///
2122
/// Our representation is a bit mixed here -- in some cases, we
2223
/// include the self type (e.g., `trait_bounds`) but in others we do not
2324
#[derive(Default, PartialEq, Eq, Clone, Debug)]
2425
pub struct Bounds<'tcx> {
25-
/// A list of region bounds on the (implicit) self type. So if you
26-
/// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but
27-
/// the `T` is not explicitly included).
28-
pub region_bounds: Vec<(ty::Binder<'tcx, ty::Region<'tcx>>, Span)>,
29-
30-
/// A list of trait bounds. So if you had `T: Debug` this would be
31-
/// `T: Debug`. Note that the self-type is explicit here.
32-
pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, ty::BoundConstness)>,
33-
34-
/// A list of projection equality bounds. So if you had `T:
35-
/// Iterator<Item = u32>` this would include `<T as
36-
/// Iterator>::Item => u32`. Note that the self-type is explicit
37-
/// here.
38-
pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
39-
40-
/// `Some` if there is *no* `?Sized` predicate. The `span`
41-
/// is the location in the source of the `T` declaration which can
42-
/// be cited as the source of the `T: Sized` requirement.
43-
pub implicitly_sized: Option<Span>,
26+
pub predicates: Vec<(ty::Predicate<'tcx>, Span)>,
4427
}
4528

4629
impl<'tcx> Bounds<'tcx> {
47-
/// Converts a bounds list into a flat set of predicates (like
48-
/// where-clauses). Because some of our bounds listings (e.g.,
49-
/// regions) don't include the self-type, you must supply the
50-
/// self-type here (the `param_ty` parameter).
51-
pub fn predicates<'out, 's>(
52-
&'s self,
30+
pub fn push_region_bound(
31+
&mut self,
5332
tcx: TyCtxt<'tcx>,
54-
param_ty: Ty<'tcx>,
55-
// the output must live shorter than the duration of the borrow of self and 'tcx.
56-
) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + 'out
57-
where
58-
'tcx: 'out,
59-
's: 'out,
60-
{
61-
// If it could be sized, and is, add the `Sized` predicate.
62-
let sized_predicate = self.implicitly_sized.and_then(|span| {
63-
// FIXME: use tcx.at(span).mk_trait_ref(LangItem::Sized) here? This may make no-core code harder to write.
64-
let sized = tcx.lang_items().sized_trait()?;
65-
let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(sized, [param_ty]));
66-
Some((trait_ref.without_const().to_predicate(tcx), span))
67-
});
33+
region: ty::PolyTypeOutlivesPredicate<'tcx>,
34+
span: Span,
35+
) {
36+
self.predicates.push((region.to_predicate(tcx), span));
37+
}
6838

69-
let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| {
70-
let pred = region_bound
71-
.map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
72-
.to_predicate(tcx);
73-
(pred, span)
74-
});
75-
let trait_bounds =
76-
self.trait_bounds.iter().map(move |&(bound_trait_ref, span, constness)| {
77-
let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
78-
(predicate, span)
79-
});
80-
let projection_bounds = self
81-
.projection_bounds
82-
.iter()
83-
.map(move |&(projection, span)| (projection.to_predicate(tcx), span));
39+
pub fn push_trait_bound(
40+
&mut self,
41+
tcx: TyCtxt<'tcx>,
42+
trait_ref: ty::PolyTraitRef<'tcx>,
43+
span: Span,
44+
constness: ty::BoundConstness,
45+
) {
46+
self.predicates.push((trait_ref.with_constness(constness).to_predicate(tcx), span));
47+
}
48+
49+
pub fn push_projection_bound(
50+
&mut self,
51+
tcx: TyCtxt<'tcx>,
52+
projection: ty::PolyProjectionPredicate<'tcx>,
53+
span: Span,
54+
) {
55+
self.predicates.push((projection.to_predicate(tcx), span));
56+
}
57+
58+
pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) {
59+
let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span));
60+
let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [ty]));
61+
// Preferrable to put this obligation first, since we report better errors for sized ambiguity.
62+
self.predicates.insert(0, (trait_ref.without_const().to_predicate(tcx), span));
63+
}
8464

85-
sized_predicate.into_iter().chain(region_preds).chain(trait_bounds).chain(projection_bounds)
65+
pub fn predicates(&self) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + '_ {
66+
self.predicates.iter().cloned()
8667
}
8768
}

compiler/rustc_hir_analysis/src/collect/item_bounds.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ fn associated_type_bounds<'tcx>(
2828
let icx = ItemCtxt::new(tcx, assoc_item_def_id);
2929
let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
3030
// Associated types are implicitly sized unless a `?Sized` bound is found
31-
<dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
31+
<dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, item_ty, ast_bounds, None, span);
3232

3333
let trait_def_id = tcx.parent(assoc_item_def_id);
3434
let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
@@ -44,9 +44,7 @@ fn associated_type_bounds<'tcx>(
4444
}
4545
});
4646

47-
let all_bounds = tcx
48-
.arena
49-
.alloc_from_iter(bounds.predicates(tcx, item_ty).into_iter().chain(bounds_from_parent));
47+
let all_bounds = tcx.arena.alloc_from_iter(bounds.predicates().chain(bounds_from_parent));
5048
debug!("associated_type_bounds({}) = {:?}", tcx.def_path_str(assoc_item_def_id), all_bounds);
5149
all_bounds
5250
}
@@ -74,10 +72,10 @@ fn opaque_type_bounds<'tcx>(
7472
let icx = ItemCtxt::new(tcx, opaque_def_id);
7573
let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
7674
// Opaque types are implicitly sized unless a `?Sized` bound is found
77-
<dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
75+
<dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, item_ty, ast_bounds, None, span);
7876
debug!(?bounds);
7977

80-
tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
78+
tcx.arena.alloc_from_iter(bounds.predicates())
8179
})
8280
}
8381

0 commit comments

Comments
 (0)