Skip to content

Commit 149bd87

Browse files
Pull out into helper function
1 parent 2dacf7a commit 149bd87

File tree

1 file changed

+112
-99
lines changed

1 file changed

+112
-99
lines changed

compiler/rustc_hir_analysis/src/collect/item_bounds.rs

+112-99
Original file line numberDiff line numberDiff line change
@@ -45,107 +45,15 @@ fn associated_type_bounds<'tcx>(
4545

4646
let item_trait_ref = ty::TraitRef::identity(tcx, tcx.parent(assoc_item_def_id.to_def_id()));
4747
let bounds_from_parent =
48-
trait_predicates.predicates.iter().copied().filter_map(|(pred, span)| {
49-
let mut clause_ty = match pred.kind().skip_binder() {
50-
ty::ClauseKind::Trait(tr) => tr.self_ty(),
51-
ty::ClauseKind::Projection(proj) => proj.projection_term.self_ty(),
52-
ty::ClauseKind::TypeOutlives(outlives) => outlives.0,
53-
_ => return None,
54-
};
55-
56-
// The code below is quite involved, so let me explain.
57-
//
58-
// We loop here, because we also want to collect vars for nested associated items as
59-
// well. For example, given a clause like `Self::A::B`, we want to add that to the
60-
// item bounds for `A`, so that we may use that bound in the case that `Self::A::B` is
61-
// rigid.
62-
//
63-
// Secondly, regarding bound vars, when we see a where clause that mentions a GAT
64-
// like `for<'a, ...> Self::Assoc<'a, ...>: Bound<'b, ...>`, we want to turn that into
65-
// an item bound on the GAT, where all of the GAT args are substituted with the GAT's
66-
// param regions, and then keep all of the other late-bound vars in the bound around.
67-
// We need to "compress" the binder so that it doesn't mention any of those vars that
68-
// were mapped to params.
69-
let gat_vars = loop {
70-
if let ty::Alias(ty::Projection, alias_ty) = *clause_ty.kind() {
71-
if alias_ty.trait_ref(tcx) == item_trait_ref
72-
&& alias_ty.def_id == assoc_item_def_id.to_def_id()
73-
{
74-
break &alias_ty.args[item_trait_ref.args.len()..];
75-
} else {
76-
// Only collect *self* type bounds if the filter is for self.
77-
match filter {
78-
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {
79-
return None;
80-
}
81-
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
82-
}
83-
}
84-
85-
clause_ty = alias_ty.self_ty();
86-
continue;
87-
}
88-
}
89-
90-
return None;
91-
};
92-
// Special-case: No GAT vars, no mapping needed.
93-
if gat_vars.is_empty() {
94-
return Some((pred, span));
95-
}
96-
97-
// First, check that all of the GAT args are substituted with a unique late-bound arg.
98-
// If we find a duplicate, then it can't be mapped to the definition's params.
99-
let mut mapping = FxIndexMap::default();
100-
let generics = tcx.generics_of(assoc_item_def_id);
101-
for (param, var) in std::iter::zip(&generics.own_params, gat_vars) {
102-
let existing = match var.unpack() {
103-
ty::GenericArgKind::Lifetime(re) => {
104-
if let ty::RegionKind::ReBound(ty::INNERMOST, bv) = re.kind() {
105-
mapping.insert(bv.var, tcx.mk_param_from_def(param))
106-
} else {
107-
return None;
108-
}
109-
}
110-
ty::GenericArgKind::Type(ty) => {
111-
if let ty::Bound(ty::INNERMOST, bv) = *ty.kind() {
112-
mapping.insert(bv.var, tcx.mk_param_from_def(param))
113-
} else {
114-
return None;
115-
}
116-
}
117-
ty::GenericArgKind::Const(ct) => {
118-
if let ty::ConstKind::Bound(ty::INNERMOST, bv) = ct.kind() {
119-
mapping.insert(bv, tcx.mk_param_from_def(param))
120-
} else {
121-
return None;
122-
}
123-
}
124-
};
125-
126-
if existing.is_some() {
127-
return None;
128-
}
129-
}
130-
131-
// Finally, map all of the args in the GAT to the params we expect, and compress
132-
// the remaining late-bound vars so that they count up from var 0.
133-
let mut folder = MapAndCompressBoundVars {
48+
trait_predicates.predicates.iter().copied().filter_map(|(clause, span)| {
49+
remap_gat_vars_and_recurse_into_nested_projections(
13450
tcx,
135-
binder: ty::INNERMOST,
136-
still_bound_vars: vec![],
137-
mapping,
138-
};
139-
let pred = pred.kind().skip_binder().fold_with(&mut folder);
140-
141-
Some((
142-
ty::Binder::bind_with_vars(
143-
pred,
144-
tcx.mk_bound_variable_kinds(&folder.still_bound_vars),
145-
)
146-
.upcast(tcx),
51+
filter,
52+
item_trait_ref,
53+
assoc_item_def_id,
14754
span,
148-
))
55+
clause,
56+
)
14957
});
15058

15159
let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent));
@@ -160,6 +68,111 @@ fn associated_type_bounds<'tcx>(
16068
all_bounds
16169
}
16270

71+
/// The code below is quite involved, so let me explain.
72+
///
73+
/// We loop here, because we also want to collect vars for nested associated items as
74+
/// well. For example, given a clause like `Self::A::B`, we want to add that to the
75+
/// item bounds for `A`, so that we may use that bound in the case that `Self::A::B` is
76+
/// rigid.
77+
///
78+
/// Secondly, regarding bound vars, when we see a where clause that mentions a GAT
79+
/// like `for<'a, ...> Self::Assoc<'a, ...>: Bound<'b, ...>`, we want to turn that into
80+
/// an item bound on the GAT, where all of the GAT args are substituted with the GAT's
81+
/// param regions, and then keep all of the other late-bound vars in the bound around.
82+
/// We need to "compress" the binder so that it doesn't mention any of those vars that
83+
/// were mapped to params.
84+
fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>(
85+
tcx: TyCtxt<'tcx>,
86+
filter: PredicateFilter,
87+
item_trait_ref: ty::TraitRef<'tcx>,
88+
assoc_item_def_id: LocalDefId,
89+
span: Span,
90+
clause: ty::Clause<'tcx>,
91+
) -> Option<(ty::Clause<'tcx>, Span)> {
92+
let mut clause_ty = match clause.kind().skip_binder() {
93+
ty::ClauseKind::Trait(tr) => tr.self_ty(),
94+
ty::ClauseKind::Projection(proj) => proj.projection_term.self_ty(),
95+
ty::ClauseKind::TypeOutlives(outlives) => outlives.0,
96+
_ => return None,
97+
};
98+
99+
let gat_vars = loop {
100+
if let ty::Alias(ty::Projection, alias_ty) = *clause_ty.kind() {
101+
if alias_ty.trait_ref(tcx) == item_trait_ref
102+
&& alias_ty.def_id == assoc_item_def_id.to_def_id()
103+
{
104+
// We have found the GAT in question...
105+
// Return the vars, since we may need to remap them.
106+
break &alias_ty.args[item_trait_ref.args.len()..];
107+
} else {
108+
// Only collect *self* type bounds if the filter is for self.
109+
match filter {
110+
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {
111+
return None;
112+
}
113+
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {}
114+
}
115+
116+
clause_ty = alias_ty.self_ty();
117+
continue;
118+
}
119+
}
120+
121+
return None;
122+
};
123+
124+
// Special-case: No GAT vars, no mapping needed.
125+
if gat_vars.is_empty() {
126+
return Some((clause, span));
127+
}
128+
129+
// First, check that all of the GAT args are substituted with a unique late-bound arg.
130+
// If we find a duplicate, then it can't be mapped to the definition's params.
131+
let mut mapping = FxIndexMap::default();
132+
let generics = tcx.generics_of(assoc_item_def_id);
133+
for (param, var) in std::iter::zip(&generics.own_params, gat_vars) {
134+
let existing = match var.unpack() {
135+
ty::GenericArgKind::Lifetime(re) => {
136+
if let ty::RegionKind::ReBound(ty::INNERMOST, bv) = re.kind() {
137+
mapping.insert(bv.var, tcx.mk_param_from_def(param))
138+
} else {
139+
return None;
140+
}
141+
}
142+
ty::GenericArgKind::Type(ty) => {
143+
if let ty::Bound(ty::INNERMOST, bv) = *ty.kind() {
144+
mapping.insert(bv.var, tcx.mk_param_from_def(param))
145+
} else {
146+
return None;
147+
}
148+
}
149+
ty::GenericArgKind::Const(ct) => {
150+
if let ty::ConstKind::Bound(ty::INNERMOST, bv) = ct.kind() {
151+
mapping.insert(bv, tcx.mk_param_from_def(param))
152+
} else {
153+
return None;
154+
}
155+
}
156+
};
157+
158+
if existing.is_some() {
159+
return None;
160+
}
161+
}
162+
163+
// Finally, map all of the args in the GAT to the params we expect, and compress
164+
// the remaining late-bound vars so that they count up from var 0.
165+
let mut folder =
166+
MapAndCompressBoundVars { tcx, binder: ty::INNERMOST, still_bound_vars: vec![], mapping };
167+
let pred = clause.kind().skip_binder().fold_with(&mut folder);
168+
169+
Some((
170+
ty::Binder::bind_with_vars(pred, tcx.mk_bound_variable_kinds(&folder.still_bound_vars))
171+
.upcast(tcx),
172+
span,
173+
))
174+
}
175+
163176
struct MapAndCompressBoundVars<'tcx> {
164177
tcx: TyCtxt<'tcx>,
165178
/// How deep are we? Makes sure we don't touch the vars of nested binders.

0 commit comments

Comments
 (0)