Skip to content

Commit 59885f5

Browse files
committed
Delegation refactoring: add builders for generics inheritance
1 parent fdf61d4 commit 59885f5

File tree

3 files changed

+214
-110
lines changed

3 files changed

+214
-110
lines changed

compiler/rustc_hir_analysis/src/delegation.rs

+184-80
Original file line numberDiff line numberDiff line change
@@ -76,41 +76,153 @@ fn fn_kind<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> FnKind {
7676
}
7777
}
7878

79+
struct GenericsBuilder<'tcx> {
80+
tcx: TyCtxt<'tcx>,
81+
sig_id: DefId,
82+
parent: Option<DefId>,
83+
}
84+
85+
impl<'tcx> GenericsBuilder<'tcx> {
86+
fn new(tcx: TyCtxt<'tcx>, sig_id: DefId) -> GenericsBuilder<'tcx> {
87+
GenericsBuilder { tcx, sig_id, parent: None }
88+
}
89+
90+
fn build(self) -> ty::Generics {
91+
let mut own_params = vec![];
92+
93+
let sig_generics = self.tcx.generics_of(self.sig_id);
94+
if let Some(parent_def_id) = sig_generics.parent {
95+
let sig_parent_generics = self.tcx.generics_of(parent_def_id);
96+
own_params.append(&mut sig_parent_generics.own_params.clone());
97+
}
98+
own_params.append(&mut sig_generics.own_params.clone());
99+
100+
// Lifetime parameters must be declared before type and const parameters.
101+
// Therefore, When delegating from a free function to a associated function,
102+
// generic parameters need to be reordered:
103+
//
104+
// trait Trait<'a, A> {
105+
// fn foo<'b, B>(...) {...}
106+
// }
107+
//
108+
// reuse Trait::foo;
109+
// desugaring:
110+
// fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) {
111+
// Trait::foo(...)
112+
// }
113+
own_params.sort_by_key(|key| key.kind.is_ty_or_const());
114+
115+
let param_def_id_to_index =
116+
own_params.iter().map(|param| (param.def_id, param.index)).collect();
117+
118+
for (idx, param) in own_params.iter_mut().enumerate() {
119+
param.index = idx as u32;
120+
// FIXME(fn_delegation): Default parameters are not inherited, because they are
121+
// not permitted in functions. Therefore, there are 2 options here:
122+
//
123+
// - We can create non-default generic parameters.
124+
// - We can substitute default parameters into the signature.
125+
//
126+
// At the moment, first option has been selected as the most general.
127+
if let ty::GenericParamDefKind::Type { has_default, .. }
128+
| ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind
129+
{
130+
*has_default = false;
131+
}
132+
}
133+
134+
ty::Generics {
135+
parent: self.parent,
136+
parent_count: 0,
137+
own_params,
138+
param_def_id_to_index,
139+
has_self: false,
140+
has_late_bound_regions: sig_generics.has_late_bound_regions,
141+
host_effect_index: sig_generics.host_effect_index,
142+
}
143+
}
144+
}
145+
146+
struct PredicatesBuilder<'tcx> {
147+
tcx: TyCtxt<'tcx>,
148+
args: ty::GenericArgsRef<'tcx>,
149+
parent: Option<DefId>,
150+
sig_id: DefId,
151+
}
152+
153+
impl<'tcx> PredicatesBuilder<'tcx> {
154+
fn new(
155+
tcx: TyCtxt<'tcx>,
156+
args: ty::GenericArgsRef<'tcx>,
157+
sig_id: DefId,
158+
) -> PredicatesBuilder<'tcx> {
159+
PredicatesBuilder { tcx, args, parent: None, sig_id }
160+
}
161+
162+
fn build(self) -> ty::GenericPredicates<'tcx> {
163+
let mut preds = vec![];
164+
165+
let sig_predicates = self.tcx.predicates_of(self.sig_id);
166+
if let Some(parent) = sig_predicates.parent {
167+
let sig_parent_preds = self.tcx.predicates_of(parent);
168+
preds.extend(sig_parent_preds.instantiate_own(self.tcx, self.args));
169+
}
170+
preds.extend(sig_predicates.instantiate_own(self.tcx, self.args));
171+
172+
ty::GenericPredicates {
173+
parent: self.parent,
174+
predicates: self.tcx.arena.alloc_from_iter(preds),
175+
// FIXME(fn_delegation): Support effects.
176+
effects_min_tys: ty::List::empty(),
177+
}
178+
}
179+
}
180+
181+
struct GenericArgsBuilder<'tcx> {
182+
tcx: TyCtxt<'tcx>,
183+
remap_table: RemapTable,
184+
sig_id: DefId,
185+
def_id: LocalDefId,
186+
}
187+
188+
impl<'tcx> GenericArgsBuilder<'tcx> {
189+
fn new(tcx: TyCtxt<'tcx>, sig_id: DefId, def_id: LocalDefId) -> GenericArgsBuilder<'tcx> {
190+
GenericArgsBuilder { tcx, remap_table: FxHashMap::default(), sig_id, def_id }
191+
}
192+
193+
fn build_from_args(mut self, args: ty::GenericArgsRef<'tcx>) -> ty::GenericArgsRef<'tcx> {
194+
let caller_generics = self.tcx.generics_of(self.def_id);
195+
let callee_generics = self.tcx.generics_of(self.sig_id);
196+
197+
for caller_param in &caller_generics.own_params {
198+
let callee_index =
199+
callee_generics.param_def_id_to_index(self.tcx, caller_param.def_id).unwrap();
200+
self.remap_table.insert(callee_index, caller_param.index);
201+
}
202+
203+
let mut folder = ParamIndexRemapper { tcx: self.tcx, remap_table: self.remap_table };
204+
args.fold_with(&mut folder)
205+
}
206+
}
207+
79208
fn create_generic_args<'tcx>(
80209
tcx: TyCtxt<'tcx>,
81210
def_id: LocalDefId,
82211
sig_id: DefId,
83212
) -> ty::GenericArgsRef<'tcx> {
84-
let caller_generics = tcx.generics_of(def_id);
85-
let callee_generics = tcx.generics_of(sig_id);
213+
let builder = GenericArgsBuilder::new(tcx, sig_id, def_id);
86214

87215
let caller_kind = fn_kind(tcx, def_id.into());
88216
let callee_kind = fn_kind(tcx, sig_id);
89-
// FIXME(fn_delegation): Support generics on associated delegation items.
90-
// Error will be reported in `check_constraints`.
217+
91218
match (caller_kind, callee_kind) {
92-
(FnKind::Free, _) => {
93-
// Lifetime parameters must be declared before type and const parameters.
94-
// Therefore, When delegating from a free function to a associated function,
95-
// generic parameters need to be reordered:
96-
//
97-
// trait Trait<'a, A> {
98-
// fn foo<'b, B>(...) {...}
99-
// }
100-
//
101-
// reuse Trait::foo;
102-
// desugaring:
103-
// fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) {
104-
// Trait::foo(...)
105-
// }
106-
let mut remap_table = RemapTable::default();
107-
for caller_param in &caller_generics.own_params {
108-
let callee_index =
109-
callee_generics.param_def_id_to_index(tcx, caller_param.def_id).unwrap();
110-
remap_table.insert(callee_index, caller_param.index);
111-
}
112-
let mut folder = ParamIndexRemapper { tcx, remap_table };
113-
ty::GenericArgs::identity_for_item(tcx, sig_id).fold_with(&mut folder)
219+
(FnKind::Free, FnKind::Free)
220+
| (FnKind::Free, FnKind::AssocTrait)
221+
| (FnKind::AssocInherentImpl, FnKind::Free)
222+
| (FnKind::AssocTrait, FnKind::Free)
223+
| (FnKind::AssocTrait, FnKind::AssocTrait) => {
224+
let args = ty::GenericArgs::identity_for_item(tcx, sig_id);
225+
builder.build_from_args(args)
114226
}
115227
// FIXME(fn_delegation): Only `Self` param supported here.
116228
(FnKind::AssocTraitImpl, FnKind::AssocTrait)
@@ -120,7 +232,11 @@ fn create_generic_args<'tcx>(
120232
let generic_self_ty = ty::GenericArg::from(self_ty);
121233
tcx.mk_args_from_iter(std::iter::once(generic_self_ty))
122234
}
123-
_ => ty::GenericArgs::identity_for_item(tcx, sig_id),
235+
// For trait impl's `sig_id` is always equal to the corresponding trait method.
236+
(FnKind::AssocTraitImpl, _)
237+
| (_, FnKind::AssocTraitImpl)
238+
// Delegation to inherent methods is not yet supported.
239+
| (_, FnKind::AssocInherentImpl) => unreachable!(),
124240
}
125241
}
126242

@@ -129,74 +245,62 @@ pub(crate) fn inherit_generics_for_delegation_item<'tcx>(
129245
def_id: LocalDefId,
130246
sig_id: DefId,
131247
) -> Option<ty::Generics> {
132-
// FIXME(fn_delegation): Support generics on associated delegation items.
133-
// Error will be reported in `check_constraints`.
134-
if fn_kind(tcx, def_id.into()) != FnKind::Free {
135-
return None;
136-
}
248+
let builder = GenericsBuilder::new(tcx, sig_id);
137249

138-
let mut own_params = vec![];
139-
140-
let callee_generics = tcx.generics_of(sig_id);
141-
if let Some(parent_sig_id) = callee_generics.parent {
142-
let parent_sig_generics = tcx.generics_of(parent_sig_id);
143-
own_params.append(&mut parent_sig_generics.own_params.clone());
144-
}
145-
own_params.append(&mut callee_generics.own_params.clone());
250+
let caller_kind = fn_kind(tcx, def_id.into());
251+
let callee_kind = fn_kind(tcx, sig_id);
146252

147-
// Lifetimes go first.
148-
own_params.sort_by_key(|key| key.kind.is_ty_or_const());
253+
// FIXME(fn_delegation): Support generics on associated delegation items.
254+
// Error will be reported in `check_constraints`.
255+
match (caller_kind, callee_kind) {
256+
(FnKind::Free, FnKind::Free)
257+
| (FnKind::Free, FnKind::AssocTrait) => Some(builder.build()),
149258

150-
for (idx, param) in own_params.iter_mut().enumerate() {
151-
param.index = idx as u32;
152-
// Default parameters are not inherited: they are not allowed
153-
// in fn's.
154-
if let ty::GenericParamDefKind::Type { has_default, .. }
155-
| ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind
156-
{
157-
*has_default = false;
158-
}
259+
(FnKind::AssocTraitImpl, FnKind::AssocTrait)
260+
| (FnKind::AssocInherentImpl, FnKind::AssocTrait)
261+
| (FnKind::AssocTrait, FnKind::AssocTrait)
262+
| (FnKind::AssocInherentImpl, FnKind::Free)
263+
| (FnKind::AssocTrait, FnKind::Free) => None,
264+
265+
// For trait impl's `sig_id` is always equal to the corresponding trait method.
266+
(FnKind::AssocTraitImpl, _)
267+
| (_, FnKind::AssocTraitImpl)
268+
// Delegation to inherent methods is not yet supported.
269+
| (_, FnKind::AssocInherentImpl) => unreachable!(),
159270
}
160-
161-
let param_def_id_to_index =
162-
own_params.iter().map(|param| (param.def_id, param.index)).collect();
163-
164-
Some(ty::Generics {
165-
parent: None,
166-
parent_count: 0,
167-
own_params,
168-
param_def_id_to_index,
169-
has_self: false,
170-
has_late_bound_regions: callee_generics.has_late_bound_regions,
171-
host_effect_index: callee_generics.host_effect_index,
172-
})
173271
}
174272

175273
pub(crate) fn inherit_predicates_for_delegation_item<'tcx>(
176274
tcx: TyCtxt<'tcx>,
177275
def_id: LocalDefId,
178276
sig_id: DefId,
179277
) -> Option<ty::GenericPredicates<'tcx>> {
278+
let args = create_generic_args(tcx, def_id, sig_id);
279+
let builder = PredicatesBuilder::new(tcx, args, sig_id);
280+
281+
let caller_kind = fn_kind(tcx, def_id.into());
282+
let callee_kind = fn_kind(tcx, sig_id);
283+
180284
// FIXME(fn_delegation): Support generics on associated delegation items.
181285
// Error will be reported in `check_constraints`.
182-
if fn_kind(tcx, def_id.into()) != FnKind::Free {
183-
return None;
184-
}
185-
186-
let callee_predicates = tcx.predicates_of(sig_id);
187-
let args = create_generic_args(tcx, def_id, sig_id);
286+
match (caller_kind, callee_kind) {
287+
(FnKind::Free, FnKind::Free)
288+
| (FnKind::Free, FnKind::AssocTrait) => {
289+
Some(builder.build())
290+
}
188291

189-
let mut preds = vec![];
190-
if let Some(parent_id) = callee_predicates.parent {
191-
preds.extend(tcx.predicates_of(parent_id).instantiate_own(tcx, args));
292+
(FnKind::AssocTraitImpl, FnKind::AssocTrait)
293+
| (FnKind::AssocInherentImpl, FnKind::AssocTrait)
294+
| (FnKind::AssocTrait, FnKind::AssocTrait)
295+
| (FnKind::AssocInherentImpl, FnKind::Free)
296+
| (FnKind::AssocTrait, FnKind::Free) => None,
297+
298+
// For trait impl's `sig_id` is always equal to the corresponding trait method.
299+
(FnKind::AssocTraitImpl, _)
300+
| (_, FnKind::AssocTraitImpl)
301+
// Delegation to inherent methods is not yet supported.
302+
| (_, FnKind::AssocInherentImpl) => unreachable!(),
192303
}
193-
preds.extend(callee_predicates.instantiate_own(tcx, args));
194-
195-
Some(ty::GenericPredicates {
196-
parent: None,
197-
predicates: tcx.arena.alloc_from_iter(preds),
198-
effects_min_tys: ty::List::empty(),
199-
})
200304
}
201305

202306
fn check_constraints<'tcx>(

0 commit comments

Comments
 (0)