Skip to content

Commit a9db350

Browse files
authored
Rollup merge of #157960 - aerooneqq:delegation-infers-in-generics, r=petrochenkov
delegation: add support for infers in generics This PR adds support for generating generic params for lifetimes and types/consts infers (`'_`. `_`). We support only single infers, if they are nested then we do nothing and eventually an error will be emitted after inheriting this unsound signature (i.e., `reuse foo::<Vec<_>>` is not supported). The basic idea is: ```rust fn foo<'a, 'b: 'b, T, const N: usize>() {} reuse foo::<'_, String, _> as bar; // Desugaring: fn bar<'b, const N: usize>() { foo::<'b, String, N>() } ``` So we generated params and lifetimes for provided infers. Note that in case of lifetimes we may have early and late bound lifetimes in child segment. We process only early-bound lifetimes as they are present in signature function generics (`tcx.generics_of(sig_id)`). Moreover since this PR we started to explicitly propagate early-bound lifetimes in generated delegation's call, so the warning about specifying lifetimes when late-bound lifetimes are present is suppressed for delegation segments. Next, we limit the number of processed infers with the number of generic params in the signature function, so if we have `fn foo<X, Y>() {}` and we wrote `reuse foo::<_, _, _, _>;` we will not generate 4 generic params in delegation, we will generate 2 (`X` and `Y`), two remaining infers will not be processed and this will result in an error. Considering free-to-trait reuses this PR extends the number of supported cases, as now we always generate `Self` generic param when needed: ```rust trait Trait<'a, X> { fn method<'b, const M: usize>(&self) where 'b:'b { } fn r#static<'b, Y, const B: bool>() { } } impl <'a, X> Trait<'a, X> for () { } reuse Trait::<'_, _>::method::<'_, _> as foo; reuse <_ as Trait<'_, _>>::method::<'_, _> as foo1; reuse <() as Trait<'_, _>>::method::<'_, _> as foo2; reuse <_ as Trait<'_, _>>::r#static::<_, _> as foo3; reuse <() as Trait<'_, _>>::r#static::<_, _> as foo4; reuse Trait::<'_, _>::r#static::<_, _> as foo5; // Desugaring: #[attr = Inline(Hint)] fn foo<'a, 'b, Self, X, const M: _>(self: _) -> _ where 'a:'a, 'b:'b { <Self as Trait::<'a, X>>::method::<'b, M>(self) } #[attr = Inline(Hint)] fn foo1<'a, 'b, Self, X, const M: _>(self: _) -> _ where 'a:'a, 'b:'b { <Self as Trait::<'a, X>>::method::<'b, M>(self) } #[attr = Inline(Hint)] fn foo2<'a, 'b, X, const M: _>(self: _) -> _ where 'a:'a, 'b:'b { <() as Trait::<'a, X>>::method::<'b, M>(self) } #[attr = Inline(Hint)] fn foo3<'a, Self, X, Y, const B: _>() -> _ where 'a:'a { <Self as Trait::<'a, X>>::r#static::<Y, B>() } #[attr = Inline(Hint)] fn foo4<'a, X, Y, const B: _>() -> _ where 'a:'a { <() as Trait::<'a, X>>::r#static::<Y, B>() } #[attr = Inline(Hint)] fn foo5<'a, Self, X, Y, const B: _>() -> _ where 'a:'a { <Self as Trait::<'a, X>>::r#static::<Y, B>() } ``` Note that we generated `Self` in `foo5` reuse. With that done the error about self-type specification is removed. Finally this PR greatly simplifies generic args for signature inheritance generation code. Part of #118212. r? @petrochenkov
2 parents 0b4e740 + 7d42183 commit a9db350

28 files changed

Lines changed: 2416 additions & 776 deletions

compiler/rustc_ast_lowering/src/delegation.rs

Lines changed: 65 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
194194
return self.generate_delegation_error(span, delegation);
195195
}
196196

197-
let mut generics = self.uplift_delegation_generics(delegation, sig_id, is_method);
197+
let mut generics = self.uplift_delegation_generics(delegation, sig_id);
198198

199199
let (body_id, call_expr_id, unused_target_expr) = self.lower_delegation_body(
200200
delegation,
@@ -404,10 +404,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
404404
hir::InferDelegationSig::Output(self.arena.alloc(hir::DelegationInfo {
405405
call_expr_id,
406406
call_path_res: self.get_resolution_id(call_path_node_id),
407-
child_args_segment_id: generics.child.args_segment_id,
408-
parent_args_segment_id: generics.parent.args_segment_id,
409-
self_ty_id: generics.self_ty_id,
410-
propagate_self_ty: generics.propagate_self_ty,
407+
child_seg_id: generics.child.args_segment_id,
408+
child_seg_id_for_sig: generics.child.segment_id_for_sig(),
409+
parent_seg_id_for_sig: generics.parent.segment_id_for_sig(),
410+
self_ty_propagation_kind: generics.self_ty_propagation_kind,
411411
group_id: {
412412
let id = match source {
413413
DelegationSource::Single => None,
@@ -625,20 +625,40 @@ impl<'hir> LoweringContext<'_, 'hir> {
625625
}),
626626
);
627627

628-
hir::QPath::Resolved(ty, self.arena.alloc(new_path))
629-
}
630-
hir::QPath::TypeRelative(ty, segment) => {
631-
let segment = self.process_segment(span, segment, &mut generics.child);
628+
// Explicitly create `Self` self-type in case of infers or static
629+
// free-to-trait reuses.
630+
let ty = match generics.self_ty_propagation_kind {
631+
Some(hir::DelegationSelfTyPropagationKind::SelfParam) => {
632+
let self_param = generics.parent.generics.find_self_param();
633+
let path = self.create_generic_arg_path(self_param);
634+
let kind = hir::TyKind::Path(path);
635+
636+
let ty = match ty {
637+
Some(ty) => hir::Ty { kind, ..ty.clone() },
638+
None => hir::Ty { kind, hir_id: self.next_id(), span },
639+
};
640+
641+
Some(&*self.arena.alloc(ty))
642+
}
643+
_ => ty,
644+
};
632645

633-
hir::QPath::TypeRelative(ty, self.arena.alloc(segment))
646+
hir::QPath::Resolved(ty, self.arena.alloc(new_path))
634647
}
648+
hir::QPath::TypeRelative(..) => unreachable!("until inherent methods are supported"),
635649
};
636650

637-
generics.self_ty_id = match new_path {
638-
hir::QPath::Resolved(ty, _) => ty,
639-
hir::QPath::TypeRelative(ty, _) => Some(ty),
651+
if let Some(hir::DelegationSelfTyPropagationKind::SelfTy(id)) =
652+
generics.self_ty_propagation_kind.as_mut()
653+
{
654+
*id = match new_path {
655+
hir::QPath::Resolved(ty, _) => {
656+
ty.expect("must contain self type as `SelfTy` propagation kind is specified")
657+
}
658+
hir::QPath::TypeRelative(ty, _) => ty,
659+
}
660+
.hir_id;
640661
}
641-
.map(|ty| ty.hir_id);
642662

643663
let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(new_path), span));
644664
let args = self.arena.alloc_from_iter(args);
@@ -662,25 +682,38 @@ impl<'hir> LoweringContext<'_, 'hir> {
662682
segment: &hir::PathSegment<'hir>,
663683
result: &mut GenericsGenerationResult<'hir>,
664684
) -> hir::PathSegment<'hir> {
665-
let details = result.generics.args_propagation_details();
666-
667-
// Always uplift generic params, because if they are not empty then they
668-
// should be generated in delegation.
669-
let generics = result.generics.into_hir_generics(self, span);
670-
let segment = if details.should_propagate {
671-
let args = generics.into_generic_args(self, span);
672-
673-
// Needed for better error messages (`trait-impl-wrong-args-count.rs` test).
674-
let args = if args.is_empty() { None } else { Some(args) };
675-
676-
hir::PathSegment { args, ..segment.clone() }
677-
} else {
678-
segment.clone()
679-
};
685+
let infer_indices = result.generics.infer_indices();
686+
result.generics.into_hir_generics(self, span);
687+
688+
let mut segment = segment.clone();
689+
let mut args_iter = result.generics.create_args_iterator();
690+
691+
let new_args = segment
692+
.args
693+
.filter(|args| !args.is_empty())
694+
.map(|args| {
695+
self.arena.alloc_from_iter(args.args.iter().enumerate().map(|(idx, arg)| {
696+
if infer_indices.contains(&idx) {
697+
args_iter.next(self, |_| arg.hir_id()).expect("arg must exist for infer")
698+
} else {
699+
*arg
700+
}
701+
}))
702+
})
703+
.unwrap_or_else(|| self.arena.alloc_from_iter(args_iter.consume_all(self)));
704+
705+
// Needed for better error messages (`trait-impl-wrong-args-count.rs` test).
706+
segment.args = (!new_args.is_empty()).then(|| {
707+
&*self.arena.alloc(hir::GenericArgs {
708+
args: new_args,
709+
constraints: &[],
710+
parenthesized: hir::GenericArgsParentheses::No,
711+
span_ext: segment.args.map_or(span, |args| args.span_ext),
712+
})
713+
});
680714

681-
if details.use_args_in_sig_inheritance {
682-
result.args_segment_id = Some(segment.hir_id);
683-
}
715+
result.args_segment_id = segment.hir_id;
716+
result.use_for_sig_inheritance = !result.generics.is_trait_impl();
684717

685718
segment
686719
}

0 commit comments

Comments
 (0)