Skip to content

Commit 3ecd955

Browse files
committed
Refactor delegation generics resolution
1 parent d9d6688 commit 3ecd955

1 file changed

Lines changed: 151 additions & 75 deletions

File tree

compiler/rustc_ast_lowering/src/delegation/generics.rs

Lines changed: 151 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -232,123 +232,199 @@ impl<'hir> GenericsGenerationResult<'hir> {
232232
}
233233
}
234234

235+
enum ParentSegmentArgs<'a> {
236+
/// Parent segment is valid and generic args are specified:
237+
/// `reuse Trait::<'static, ()>::foo;`.
238+
Specified(&'a AngleBracketedArgs),
239+
/// Parent segment is valid and args are not specified:
240+
/// `reuse Trait::foo;`.
241+
NotSpecified,
242+
/// Parent segment doest not exist (`reuse foo`) or we can not
243+
/// add generics to it:
244+
/// ```rust
245+
/// mod to_reuse {
246+
/// fn foo() {}
247+
/// }
248+
///
249+
/// // Can't add generic args to module.
250+
/// reuse to_reuse::foo;
251+
/// ```
252+
Invalid,
253+
}
254+
255+
struct GenericsResolutionDto<'a, 'tcx> {
256+
trait_impl: bool,
257+
258+
parent_args: ParentSegmentArgs<'a>,
259+
child_args: Option<&'a AngleBracketedArgs>,
260+
261+
sig_parent_params: &'tcx [ty::GenericParamDef],
262+
sig_child_params: &'tcx [ty::GenericParamDef],
263+
264+
free_to_trait_delegation: bool,
265+
/// `reuse Trait::foo;`.
266+
qself_is_none: bool,
267+
/// `reuse <_ as Trait>::foo;`.
268+
qself_is_infer: bool,
269+
/// Whether we should generate `Self` generic param.
270+
generate_self: bool,
271+
}
272+
235273
impl<'hir, T: LoweringContextForResolution<'hir>> DelegationResolverForLowering<'_, T> {
236-
pub(super) fn resolve_generics(
274+
fn create_resolution_dto<'a>(
237275
&self,
238-
delegation: &Delegation,
276+
delegation: &'a Delegation,
239277
sig_id: DefId,
240-
) -> GenericsGenerationResults<'hir> {
278+
) -> GenericsResolutionDto<'a, 'hir> {
241279
let tcx = self.0.tcx();
242-
243280
let delegation_parent_kind = tcx.def_kind(tcx.local_parent(self.0.owner_id()));
244281

245-
let segments = &delegation.path.segments;
246-
let len = segments.len();
282+
let trait_impl = matches!(delegation_parent_kind, DefKind::Impl { of_trait: true });
283+
284+
let delegation_in_free_ctx =
285+
!matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. });
286+
287+
let sig_parent = tcx.parent(sig_id);
288+
let sig_in_trait = matches!(tcx.def_kind(sig_parent), DefKind::Trait);
289+
let free_to_trait_delegation = delegation_in_free_ctx && sig_in_trait;
290+
291+
let sig_child_params = &tcx.generics_of(sig_id).own_params;
292+
let mut sig_parent_params: &[ty::GenericParamDef] = &[];
247293

248-
let get_user_args = |idx: usize| -> Option<&AngleBracketedArgs> {
249-
let segment = &segments[idx];
294+
let qself_is_infer =
295+
delegation.qself.as_ref().is_some_and(|qself| qself.ty.is_maybe_parenthesised_infer());
250296

251-
let Some(args) = segment.args.as_ref() else { return None };
252-
let GenericArgs::AngleBracketed(args) = args else {
253-
tcx.dcx().span_delayed_bug(
254-
segment.span(),
255-
"expected angle-bracketed generic args in delegation segment",
256-
);
297+
let qself_is_none = delegation.qself.is_none();
298+
let generate_self = free_to_trait_delegation && (qself_is_none || qself_is_infer);
257299

258-
return None;
259-
};
300+
let parent_args = if let [.., parent_segment, _] = &delegation.path.segments[..] {
301+
if let Some(res) = self.0.get_resolution_id(parent_segment.id)
302+
&& matches!(tcx.def_kind(res), DefKind::Trait | DefKind::TraitAlias)
303+
{
304+
sig_parent_params = &tcx.generics_of(sig_parent).own_params;
305+
self.get_user_args(parent_segment)
306+
.map(|args| ParentSegmentArgs::Specified(args))
307+
.unwrap_or(ParentSegmentArgs::NotSpecified)
308+
} else {
309+
ParentSegmentArgs::Invalid
310+
}
311+
} else {
312+
ParentSegmentArgs::Invalid
313+
};
314+
315+
let child_segment = delegation.path.segments.last().expect("must be at least one segment");
316+
let child_args = self.get_user_args(child_segment);
317+
318+
GenericsResolutionDto {
319+
trait_impl,
320+
parent_args,
321+
child_args,
322+
sig_parent_params,
323+
sig_child_params,
324+
free_to_trait_delegation,
325+
qself_is_none,
326+
qself_is_infer,
327+
generate_self,
328+
}
329+
}
330+
331+
fn get_user_args<'a>(&self, segment: &'a PathSegment) -> Option<&'a AngleBracketedArgs> {
332+
let Some(args) = segment.args.as_ref() else { return None };
333+
let GenericArgs::AngleBracketed(args) = args else {
334+
self.0.tcx().dcx().span_delayed_bug(
335+
segment.span(),
336+
"expected angle-bracketed generic args in delegation segment",
337+
);
260338

261-
// Treat empty args `reuse foo::<> as bar` as `reuse foo as bar`,
262-
// the same logic applied when we call function `fn f<T>(t: T)`
263-
// like that `f::<>(())`, in HIR no `<>` will be generated.
264-
(!args.args.is_empty()).then(|| args)
339+
return None;
265340
};
266341

267-
let sig_params = &tcx.generics_of(sig_id).own_params[..];
342+
// Treat empty args `reuse foo::<> as bar` as `reuse foo as bar`,
343+
// the same logic applied when we call function `fn f<T>(t: T)`
344+
// like that `f::<>(())`, in HIR no `<>` will be generated.
345+
(!args.args.is_empty()).then(|| args)
346+
}
347+
348+
pub(super) fn resolve_generics(
349+
&self,
350+
delegation: &Delegation,
351+
sig_id: DefId,
352+
) -> GenericsGenerationResults<'hir> {
353+
let dto @ GenericsResolutionDto { trait_impl, generate_self, sig_child_params, .. } =
354+
self.create_resolution_dto(delegation, sig_id);
268355

269356
// If we are in trait impl always generate function whose generics matches
270357
// those that are defined in trait.
271-
if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) {
358+
if trait_impl {
272359
// Considering parent generics, during signature inheritance
273360
// we will take those args that are in trait impl header trait ref.
274361
let parent =
275362
DelegationGenerics { data: vec![], pos: GenericsPosition::Child, trait_impl: true };
276363

277364
let parent = GenericsGenerationResult::new(parent);
278365

279-
let child = DelegationGenerics::generate_all(sig_params, GenericsPosition::Child, true);
366+
let child = DelegationGenerics::generate_all(
367+
dto.sig_child_params,
368+
GenericsPosition::Child,
369+
true,
370+
);
371+
280372
let child = GenericsGenerationResult::new(child);
281373

282374
return GenericsGenerationResults { parent, child, self_ty_propagation_kind: None };
283375
}
284376

285-
let delegation_in_free_ctx =
286-
!matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. });
287-
288-
let sig_parent = tcx.parent(sig_id);
289-
let sig_in_trait = matches!(tcx.def_kind(sig_parent), DefKind::Trait);
290-
let free_to_trait_delegation = delegation_in_free_ctx && sig_in_trait;
291-
292-
let qself_is_infer =
293-
delegation.qself.as_ref().is_some_and(|qself| qself.ty.is_maybe_parenthesised_infer());
294-
295-
let qself_is_none = delegation.qself.is_none();
296-
297-
let generate_self = free_to_trait_delegation && (qself_is_none || qself_is_infer);
298-
299-
let can_add_generics_to_parent = len >= 2
300-
&& self.0.get_resolution_id(segments[len - 2].id).is_some_and(|def_id| {
301-
matches!(tcx.def_kind(def_id), DefKind::Trait | DefKind::TraitAlias)
302-
});
303-
304-
let parent_generics = if can_add_generics_to_parent {
305-
let sig_parent_params = &tcx.generics_of(sig_parent).own_params;
306-
307-
if let Some(args) = get_user_args(len - 2) {
308-
DelegationGenerics {
309-
data: Self::create_slots_from_args(
310-
tcx,
311-
args,
312-
&sig_parent_params[usize::from(!generate_self)..],
313-
generate_self,
314-
),
315-
pos: GenericsPosition::Parent,
316-
trait_impl: false,
317-
}
318-
} else {
319-
DelegationGenerics::generate_all(
320-
&sig_parent_params[usize::from(!generate_self)..],
321-
GenericsPosition::Parent,
322-
false,
323-
)
377+
let tcx = self.0.tcx();
378+
let parent_generics = match dto.parent_args {
379+
ParentSegmentArgs::Specified(args) => DelegationGenerics {
380+
data: Self::create_slots_from_args(
381+
tcx,
382+
args,
383+
&dto.sig_parent_params[usize::from(!generate_self)..],
384+
generate_self,
385+
),
386+
pos: GenericsPosition::Parent,
387+
trait_impl,
388+
},
389+
ParentSegmentArgs::NotSpecified => DelegationGenerics::generate_all(
390+
&dto.sig_parent_params[usize::from(!generate_self)..],
391+
GenericsPosition::Parent,
392+
trait_impl,
393+
),
394+
ParentSegmentArgs::Invalid => {
395+
DelegationGenerics { data: vec![], pos: GenericsPosition::Parent, trait_impl }
324396
}
325-
} else {
326-
DelegationGenerics { data: vec![], pos: GenericsPosition::Parent, trait_impl: false }
327397
};
328398

329-
let child_generics = if let Some(args) = get_user_args(len - 1) {
330-
let synth_params_index =
331-
sig_params.iter().position(|p| p.kind.is_synthetic()).unwrap_or(sig_params.len());
399+
let child_generics = if let Some(args) = dto.child_args {
400+
let synth_params_index = sig_child_params
401+
.iter()
402+
.position(|p| p.kind.is_synthetic())
403+
.unwrap_or(sig_child_params.len());
332404

333-
let mut slots =
334-
Self::create_slots_from_args(tcx, args, &sig_params[..synth_params_index], false);
405+
let mut slots = Self::create_slots_from_args(
406+
tcx,
407+
args,
408+
&dto.sig_child_params[..synth_params_index],
409+
trait_impl,
410+
);
335411

336-
for synth_param in &sig_params[synth_params_index..] {
412+
for synth_param in &sig_child_params[synth_params_index..] {
337413
slots.push(GenericArgSlot::Generate(synth_param, None));
338414
}
339415

340-
DelegationGenerics { data: slots, pos: GenericsPosition::Child, trait_impl: false }
416+
DelegationGenerics { data: slots, pos: GenericsPosition::Child, trait_impl }
341417
} else {
342-
DelegationGenerics::generate_all(sig_params, GenericsPosition::Child, false)
418+
DelegationGenerics::generate_all(sig_child_params, GenericsPosition::Child, trait_impl)
343419
};
344420

345421
GenericsGenerationResults {
346422
parent: GenericsGenerationResult::new(parent_generics),
347423
child: GenericsGenerationResult::new(child_generics),
348-
self_ty_propagation_kind: match free_to_trait_delegation {
349-
true => Some(match qself_is_none {
424+
self_ty_propagation_kind: match dto.free_to_trait_delegation {
425+
true => Some(match dto.qself_is_none {
350426
true => hir::DelegationSelfTyPropagationKind::SelfParam,
351-
false => match qself_is_infer {
427+
false => match dto.qself_is_infer {
352428
true => hir::DelegationSelfTyPropagationKind::SelfParam,
353429
// HirId is filled during generic args propagation.
354430
false => hir::DelegationSelfTyPropagationKind::SelfTy(HirId::INVALID),

0 commit comments

Comments
 (0)