Skip to content

Commit b044e63

Browse files
Pull out into helper function
1 parent b528120 commit b044e63

File tree

1 file changed

+111
-98
lines changed

1 file changed

+111
-98
lines changed

compiler/rustc_hir_analysis/src/collect/item_bounds.rs

+111-98
Original file line numberDiff line numberDiff line change
@@ -44,116 +44,129 @@ fn associated_type_bounds<'tcx>(
4444

4545
let item_trait_ref = ty::TraitRef::identity(tcx, tcx.parent(assoc_item_def_id.to_def_id()));
4646
let bounds_from_parent =
47-
trait_predicates.predicates.iter().copied().filter_map(|(pred, span)| {
48-
let mut clause_ty = match pred.kind().skip_binder() {
49-
ty::ClauseKind::Trait(tr) => tr.self_ty(),
50-
ty::ClauseKind::Projection(proj) => proj.projection_term.self_ty(),
51-
ty::ClauseKind::TypeOutlives(outlives) => outlives.0,
52-
_ => return None,
53-
};
47+
trait_predicates.predicates.iter().copied().filter_map(|(clause, span)| {
48+
remap_gat_vars_and_recurse_into_nested_projections(
49+
tcx,
50+
filter,
51+
item_trait_ref,
52+
assoc_item_def_id,
53+
span,
54+
clause,
55+
)
56+
});
5457

55-
// The code below is quite involved, so let me explain.
56-
//
57-
// We loop here, because we also want to collect vars for nested associated items as
58-
// well. For example, given a clause like `Self::A::B`, we want to add that to the
59-
// item bounds for `A`, so that we may use that bound in the case that `Self::A::B` is
60-
// rigid.
61-
//
62-
// Secondly, regarding bound vars, when we see a where clause that mentions a GAT
63-
// like `for<'a, ...> Self::Assoc<'a, ...>: Bound<'b, ...>`, we want to turn that into
64-
// an item bound on the GAT, where all of the GAT args are substituted with the GAT's
65-
// param regions, and then keep all of the other late-bound vars in the bound around.
66-
// We need to "compress" the binder so that it doesn't mention any of those vars that
67-
// were mapped to params.
68-
let gat_vars = loop {
69-
if let ty::Alias(ty::Projection, alias_ty) = *clause_ty.kind() {
70-
if alias_ty.trait_ref(tcx) == item_trait_ref
71-
&& alias_ty.def_id == assoc_item_def_id.to_def_id()
72-
{
73-
break &alias_ty.args[item_trait_ref.args.len()..];
74-
} else {
75-
// Only collect *self* type bounds if the filter is for self.
76-
match filter {
77-
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {
78-
return None;
79-
}
80-
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
81-
}
82-
}
83-
84-
clause_ty = alias_ty.self_ty();
85-
continue;
58+
let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent));
59+
debug!(
60+
"associated_type_bounds({}) = {:?}",
61+
tcx.def_path_str(assoc_item_def_id.to_def_id()),
62+
all_bounds
63+
);
64+
all_bounds
65+
}
66+
67+
/// The code below is quite involved, so let me explain.
68+
///
69+
/// We loop here, because we also want to collect vars for nested associated items as
70+
/// well. For example, given a clause like `Self::A::B`, we want to add that to the
71+
/// item bounds for `A`, so that we may use that bound in the case that `Self::A::B` is
72+
/// rigid.
73+
///
74+
/// Secondly, regarding bound vars, when we see a where clause that mentions a GAT
75+
/// like `for<'a, ...> Self::Assoc<'a, ...>: Bound<'b, ...>`, we want to turn that into
76+
/// an item bound on the GAT, where all of the GAT args are substituted with the GAT's
77+
/// param regions, and then keep all of the other late-bound vars in the bound around.
78+
/// We need to "compress" the binder so that it doesn't mention any of those vars that
79+
/// were mapped to params.
80+
fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>(
81+
tcx: TyCtxt<'tcx>,
82+
filter: PredicateFilter,
83+
item_trait_ref: ty::TraitRef<'tcx>,
84+
assoc_item_def_id: LocalDefId,
85+
span: Span,
86+
clause: ty::Clause<'tcx>,
87+
) -> Option<(ty::Clause<'tcx>, Span)> {
88+
let mut clause_ty = match clause.kind().skip_binder() {
89+
ty::ClauseKind::Trait(tr) => tr.self_ty(),
90+
ty::ClauseKind::Projection(proj) => proj.projection_term.self_ty(),
91+
ty::ClauseKind::TypeOutlives(outlives) => outlives.0,
92+
_ => return None,
93+
};
94+
95+
let gat_vars = loop {
96+
if let ty::Alias(ty::Projection, alias_ty) = *clause_ty.kind() {
97+
if alias_ty.trait_ref(tcx) == item_trait_ref
98+
&& alias_ty.def_id == assoc_item_def_id.to_def_id()
99+
{
100+
// We have found the GAT in question...
101+
// Return the vars, since we may need to remap them.
102+
break &alias_ty.args[item_trait_ref.args.len()..];
103+
} else {
104+
// Only collect *self* type bounds if the filter is for self.
105+
match filter {
106+
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {
107+
return None;
86108
}
109+
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {}
87110
}
88111

89-
return None;
90-
};
91-
// Special-case: No GAT vars, no mapping needed.
92-
if gat_vars.is_empty() {
93-
return Some((pred, span));
112+
clause_ty = alias_ty.self_ty();
113+
continue;
94114
}
115+
}
95116

96-
// First, check that all of the GAT args are substituted with a unique late-bound arg.
97-
// If we find a duplicate, then it can't be mapped to the definition's params.
98-
let mut mapping = FxIndexMap::default();
99-
let generics = tcx.generics_of(assoc_item_def_id);
100-
for (param, var) in std::iter::zip(&generics.own_params, gat_vars) {
101-
let existing = match var.unpack() {
102-
ty::GenericArgKind::Lifetime(re) => {
103-
if let ty::RegionKind::ReBound(ty::INNERMOST, bv) = re.kind() {
104-
mapping.insert(bv.var, tcx.mk_param_from_def(param))
105-
} else {
106-
return None;
107-
}
108-
}
109-
ty::GenericArgKind::Type(ty) => {
110-
if let ty::Bound(ty::INNERMOST, bv) = *ty.kind() {
111-
mapping.insert(bv.var, tcx.mk_param_from_def(param))
112-
} else {
113-
return None;
114-
}
115-
}
116-
ty::GenericArgKind::Const(ct) => {
117-
if let ty::ConstKind::Bound(ty::INNERMOST, bv) = ct.kind() {
118-
mapping.insert(bv, tcx.mk_param_from_def(param))
119-
} else {
120-
return None;
121-
}
122-
}
123-
};
117+
return None;
118+
};
124119

125-
if existing.is_some() {
120+
// Special-case: No GAT vars, no mapping needed.
121+
if gat_vars.is_empty() {
122+
return Some((clause, span));
123+
}
124+
125+
// First, check that all of the GAT args are substituted with a unique late-bound arg.
126+
// If we find a duplicate, then it can't be mapped to the definition's params.
127+
let mut mapping = FxIndexMap::default();
128+
let generics = tcx.generics_of(assoc_item_def_id);
129+
for (param, var) in std::iter::zip(&generics.own_params, gat_vars) {
130+
let existing = match var.unpack() {
131+
ty::GenericArgKind::Lifetime(re) => {
132+
if let ty::RegionKind::ReBound(ty::INNERMOST, bv) = re.kind() {
133+
mapping.insert(bv.var, tcx.mk_param_from_def(param))
134+
} else {
126135
return None;
127136
}
128137
}
138+
ty::GenericArgKind::Type(ty) => {
139+
if let ty::Bound(ty::INNERMOST, bv) = *ty.kind() {
140+
mapping.insert(bv.var, tcx.mk_param_from_def(param))
141+
} else {
142+
return None;
143+
}
144+
}
145+
ty::GenericArgKind::Const(ct) => {
146+
if let ty::ConstKind::Bound(ty::INNERMOST, bv) = ct.kind() {
147+
mapping.insert(bv, tcx.mk_param_from_def(param))
148+
} else {
149+
return None;
150+
}
151+
}
152+
};
129153

130-
// Finally, map all of the args in the GAT to the params we expect, and compress
131-
// the remaining late-bound vars so that they count up from var 0.
132-
let mut folder = MapAndCompressBoundVars {
133-
tcx,
134-
binder: ty::INNERMOST,
135-
still_bound_vars: vec![],
136-
mapping,
137-
};
138-
let pred = pred.kind().skip_binder().fold_with(&mut folder);
139-
140-
Some((
141-
ty::Binder::bind_with_vars(
142-
pred,
143-
tcx.mk_bound_variable_kinds(&folder.still_bound_vars),
144-
)
145-
.upcast(tcx),
146-
span,
147-
))
148-
});
154+
if existing.is_some() {
155+
return None;
156+
}
157+
}
149158

150-
let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent));
151-
debug!(
152-
"associated_type_bounds({}) = {:?}",
153-
tcx.def_path_str(assoc_item_def_id.to_def_id()),
154-
all_bounds
155-
);
156-
all_bounds
159+
// Finally, map all of the args in the GAT to the params we expect, and compress
160+
// the remaining late-bound vars so that they count up from var 0.
161+
let mut folder =
162+
MapAndCompressBoundVars { tcx, binder: ty::INNERMOST, still_bound_vars: vec![], mapping };
163+
let pred = clause.kind().skip_binder().fold_with(&mut folder);
164+
165+
Some((
166+
ty::Binder::bind_with_vars(pred, tcx.mk_bound_variable_kinds(&folder.still_bound_vars))
167+
.upcast(tcx),
168+
span,
169+
))
157170
}
158171

159172
struct MapAndCompressBoundVars<'tcx> {

0 commit comments

Comments
 (0)