Skip to content

Commit 0daab3a

Browse files
committed
Implement AST -> HIR generics propagation in delegation
1 parent b3869b9 commit 0daab3a

42 files changed

Lines changed: 1626 additions & 3565 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

compiler/rustc_ast_lowering/src/delegation.rs

Lines changed: 124 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ use rustc_ast::*;
4646
use rustc_attr_parsing::{AttributeParser, ShouldEmit};
4747
use rustc_data_structures::fx::FxHashSet;
4848
use rustc_errors::ErrorGuaranteed;
49-
use rustc_hir::Target;
5049
use rustc_hir::attrs::{AttributeKind, InlineAttr};
5150
use rustc_hir::def_id::{DefId, LocalDefId};
5251
use rustc_middle::span_bug;
@@ -56,9 +55,14 @@ use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
5655
use smallvec::SmallVec;
5756
use {rustc_ast as ast, rustc_hir as hir};
5857

59-
use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode};
58+
use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults};
6059
use crate::errors::{CycleInDelegationSignatureResolution, UnresolvedDelegationCallee};
61-
use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt};
60+
use crate::{
61+
AllowReturnTypeNotation, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LoweringContext,
62+
ParamMode, ResolverAstLoweringExt,
63+
};
64+
65+
mod generics;
6266

6367
pub(crate) struct DelegationResults<'hir> {
6468
pub body_id: hir::BodyId,
@@ -184,18 +188,48 @@ impl<'hir> LoweringContext<'_, 'hir> {
184188
// we need a function to extract this information
185189
let (param_count, c_variadic) = self.param_count(root_function_id);
186190

191+
let mut generics = self.lower_delegation_generics(
192+
delegation,
193+
ids.root_function_id(),
194+
item_id,
195+
span,
196+
);
197+
198+
let body_id = self.lower_delegation_body(
199+
delegation,
200+
item_id,
201+
is_method,
202+
param_count,
203+
&mut generics,
204+
span,
205+
);
206+
187207
// Here we use `delegee_id`, as this id will then be used to calculate parent for generics
188208
// inheritance, and we want this id to point on a delegee, not on the original
189209
// function (see https://github.com/rust-lang/rust/issues/150152#issuecomment-3674834654)
190-
let decl = self.lower_delegation_decl(delegee_id, param_count, c_variadic, span);
210+
let decl = self.lower_delegation_decl(
211+
delegee_id,
212+
param_count,
213+
c_variadic,
214+
span,
215+
&generics,
216+
);
191217

192218
// Here we pass `root_function_id` as we want to inherit signature (including consts, async)
193219
// from the root function that started delegation
194220
let sig = self.lower_delegation_sig(root_function_id, decl, span);
195-
196-
let body_id = self.lower_delegation_body(delegation, is_method, param_count, span);
197221
let ident = self.lower_ident(delegation.ident);
198-
let generics = self.lower_delegation_generics(span);
222+
223+
let generics = self.arena.alloc(hir::Generics {
224+
has_where_clause_predicates: false,
225+
params: self.arena.alloc_from_iter(generics.all_params(item_id, span, self)),
226+
predicates: self
227+
.arena
228+
.alloc_from_iter(generics.all_predicates(item_id, span, self)),
229+
span,
230+
where_clause_span: span,
231+
});
232+
199233
DelegationResults { body_id, sig, ident, generics }
200234
}
201235
Err(err) => self.generate_delegation_error(err, span, delegation),
@@ -295,7 +329,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
295329
self.tcx.sess,
296330
attrs,
297331
None,
298-
Target::Fn,
332+
hir::Target::Fn,
299333
DUMMY_SP,
300334
DUMMY_NODE_ID,
301335
Some(self.tcx.features()),
@@ -364,16 +398,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
364398
self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id())
365399
}
366400

367-
fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> {
368-
self.arena.alloc(hir::Generics {
369-
params: &[],
370-
predicates: &[],
371-
has_where_clause_predicates: false,
372-
where_clause_span: span,
373-
span,
374-
})
375-
}
376-
377401
// Function parameter count, including C variadic `...` if present.
378402
fn param_count(&self, def_id: DefId) -> (usize, bool /*c_variadic*/) {
379403
if let Some(local_sig_id) = def_id.as_local() {
@@ -393,6 +417,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
393417
param_count: usize,
394418
c_variadic: bool,
395419
span: Span,
420+
generics: &GenericsGenerationResults<'hir>,
396421
) -> &'hir hir::FnDecl<'hir> {
397422
// The last parameter in C variadic functions is skipped in the signature,
398423
// like during regular lowering.
@@ -405,7 +430,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
405430

406431
let output = self.arena.alloc(hir::Ty {
407432
hir_id: self.next_id(),
408-
kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Output),
433+
kind: hir::TyKind::InferDelegation(
434+
sig_id,
435+
hir::InferDelegationKind::Output(self.arena.alloc(hir::DelegationGenerics {
436+
child_args_segment_id: generics.child.args_segment_id,
437+
parent_args_segment_id: generics.parent.args_segment_id,
438+
})),
439+
),
409440
span,
410441
});
411442

@@ -460,6 +491,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
460491
abi: sig.abi,
461492
}
462493
};
494+
463495
hir::FnSig { decl, header, span }
464496
}
465497

@@ -501,6 +533,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
501533
} else {
502534
Symbol::intern(&format!("arg{idx}"))
503535
};
536+
504537
let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment {
505538
ident: Ident::with_dummy_span(name),
506539
hir_id: self.next_id(),
@@ -516,8 +549,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
516549
fn lower_delegation_body(
517550
&mut self,
518551
delegation: &Delegation,
552+
item_id: NodeId,
519553
is_method: bool,
520554
param_count: usize,
555+
generics: &mut GenericsGenerationResults<'hir>,
521556
span: Span,
522557
) -> BodyId {
523558
let block = delegation.body.as_deref();
@@ -548,7 +583,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
548583
args.push(arg);
549584
}
550585

551-
let final_expr = this.finalize_body_lowering(delegation, args, span);
586+
let final_expr = this.finalize_body_lowering(delegation, item_id, args, generics, span);
587+
552588
(this.arena.alloc_from_iter(parameters), final_expr)
553589
})
554590
}
@@ -584,7 +620,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
584620
fn finalize_body_lowering(
585621
&mut self,
586622
delegation: &Delegation,
623+
item_id: NodeId,
587624
args: Vec<hir::Expr<'hir>>,
625+
generics: &mut GenericsGenerationResults<'hir>,
588626
span: Span,
589627
) -> hir::Expr<'hir> {
590628
let args = self.arena.alloc_from_iter(args);
@@ -609,6 +647,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
609647
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
610648
None,
611649
);
650+
651+
// FIXME(fn_delegation): proper support for parent generics propagation
652+
// in method call scenario.
653+
let segment = self.process_segment(item_id, span, &segment, &mut generics.child, false);
612654
let segment = self.arena.alloc(segment);
613655

614656
self.arena.alloc(hir::Expr {
@@ -627,9 +669,41 @@ impl<'hir> LoweringContext<'_, 'hir> {
627669
None,
628670
);
629671

630-
let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(path), span));
672+
let new_path = match path {
673+
hir::QPath::Resolved(ty, path) => {
674+
let mut new_path = path.clone();
675+
let len = new_path.segments.len();
676+
677+
new_path.segments = self.arena.alloc_from_iter(
678+
new_path.segments.iter().enumerate().map(|(idx, segment)| {
679+
let mut process_segment = |result, add_lifetimes| {
680+
self.process_segment(item_id, span, segment, result, add_lifetimes)
681+
};
682+
683+
if idx + 2 == len {
684+
process_segment(&mut generics.parent, true)
685+
} else if idx + 1 == len {
686+
process_segment(&mut generics.child, false)
687+
} else {
688+
segment.clone()
689+
}
690+
}),
691+
);
692+
693+
hir::QPath::Resolved(ty, self.arena.alloc(new_path))
694+
}
695+
hir::QPath::TypeRelative(ty, segment) => {
696+
let segment =
697+
self.process_segment(item_id, span, segment, &mut generics.child, false);
698+
699+
hir::QPath::TypeRelative(ty, self.arena.alloc(segment))
700+
}
701+
};
702+
703+
let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(new_path), span));
631704
self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span))
632705
};
706+
633707
let block = self.arena.alloc(hir::Block {
634708
stmts: &[],
635709
expr: Some(call),
@@ -642,14 +716,40 @@ impl<'hir> LoweringContext<'_, 'hir> {
642716
self.mk_expr(hir::ExprKind::Block(block, None), span)
643717
}
644718

719+
fn process_segment(
720+
&mut self,
721+
item_id: NodeId,
722+
span: Span,
723+
segment: &hir::PathSegment<'hir>,
724+
result: &mut GenericsGenerationResult<'hir>,
725+
add_lifetimes: bool,
726+
) -> hir::PathSegment<'hir> {
727+
// The first condition is needed when there is SelfAndUserSpecified case,
728+
// we don't want to propagate generics params in this situation.
729+
let segment = if !result.generics.is_user_specified()
730+
&& let Some(args) = result
731+
.generics
732+
.into_hir_generics(self, item_id, span)
733+
.into_generic_args(self, add_lifetimes, span)
734+
{
735+
hir::PathSegment { args: Some(args), ..segment.clone() }
736+
} else {
737+
segment.clone()
738+
};
739+
740+
if result.generics.is_user_specified() {
741+
result.args_segment_id = Some(segment.hir_id);
742+
}
743+
744+
segment
745+
}
746+
645747
fn generate_delegation_error(
646748
&mut self,
647749
err: ErrorGuaranteed,
648750
span: Span,
649751
delegation: &Delegation,
650752
) -> DelegationResults<'hir> {
651-
let generics = self.lower_delegation_generics(span);
652-
653753
let decl = self.arena.alloc(hir::FnDecl {
654754
inputs: &[],
655755
output: hir::FnRetTy::DefaultReturn(span),
@@ -696,6 +796,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
696796
(&[], this.mk_expr(body_expr, span))
697797
});
698798

799+
let generics = hir::Generics::empty();
699800
DelegationResults { ident, generics, body_id, sig }
700801
}
701802

0 commit comments

Comments
 (0)